Tistory View

Orientation(방향) 알아내기

안드로이드 기기의 방향(orientation)은 Portrait(세로)과 Landscape(가로)가 있습니다.

보통 이 두가지의 방향에 따라 UI의 배치를 바꾸게 됩니다. 여기까지만 필요한 상황이면 다음의 코드로 해결할 수 있습니다.


우선 AndroidMainfest.xml파일에서 해당하는 Activity에 다음의 코드를 추가합니다.



android
:configChanges="keyboardHidden|orientation"



혹시나 configChanges에 다른 것이 이미 있다면, orientation만 | 를 사용하여 추가합니다. 위 한줄을 추가하는 것이 아닙니다..



그리고 activity에 onConfigurationChanged함수를 Override합니다.



public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);

if( newConfig.orientation == ORIENTATION_LANDSCAPE ) {
    // 가로모드
}
else {
    // 세로모드
}
}



가로모드/세로모드에 따라서 원하는 작업을 해주면 됩니다.




최초에 실행하기

하지만 이 onConfigurationChanged함수는 Activity생성시(onCreate)에는 호출이 안될 수 있으니 다음과 같이 onCreate함수에서도 한번 작업을 해줍니다. onCreate함수의 적당한 위치에 다음의 코드를 넣어 처음 생성될 때, 처리되도록 해주면 됩니다.

Resources r = Resources.getSystem();
Configuration config = r.getConfiguration();
if( config.orientation == ORIENTATION_LANDSCAPE ) {
    // 가로모드
}
else {
    // 세로모드
}



하지만, 필자가 원하는 것은 기기의 방향이 왼쪽으로 누운 가로모드 인지, 오른쪽으로 누운 가로모드 인지까지 알아야 될 일이 생겼습니다.





기기의 Rotation 알아내기


코드는 다음과 같습니다.

Display display = (YourActivity).getWindowManager().getDefaultDisplay();


float newRotation = 0.0f;

switch( display.getRotation() )
{
case Surface.ROTATION_0:
// 스마트폰 세로
break;
case Surface.ROTATION_90:
// 스마트폰 왼쪽으로 누음
break;
case Surface.ROTATION_180:
// 스마트폰은 보통 거꾸로를 지원하지 않는다. 따라서 스마트폰은 여기에 오지를 않는다.
break;
case Surface.ROTATION_270:
// 스마트폰 오른쪽으로 누음

break;
}


이렇게 처리하면 기기가 어느 방향을 향하고 있는 지 알아 낼 수 있습니다.

하지만... 뭐 안드로이드 프로그래밍하면서 한번에 될 일이 있겠습니까?(구글 꾸짐), 이 코드를 onConfigurationChanged에 넣어서 사용할 경우, 다른 문제가 발생합니다. 스마트폰을 왼쪽으로 누운가로모드에서 180도 홱~ 돌려서 오른쪽 가로모드로 바꿀 경우, 이미 화면에 UI는 바뀌었지만 onConfigurationChanged가 호출되지 않습니다.



다행이 API17(젤리빈MR1)부터는 다음의 방식을 사용할 수 있습니다. API17부터 사용이 가능하기 때문에, 사실상 ICS사용자에게는 정확한 동작을 할 수 없습니다. ICS는 그냥 여기까지만 지원하는 걸로 마무리하고..



DisplayManager의 DisplayListener

DisplayManager의 DisplayListener를 등록하여 사용하면 화면의 방향이 변할 때마다 알아낼 수 있습니다.


onCreate함수에 다음의 코드를 추가합니다.


if(Build.VERSION.SDK_INT >= 17 ) {
DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() {
@Override
public void onDisplayAdded(int displayId) {

}

@Override
public void onDisplayChanged(int displayId) {

Display display = YourActivity.this.getWindowManager().getDefaultDisplay();


// 방향에 따라 처리
switch( display.getRotation() )
{
case Surface.ROTATION_0:

break;
case Surface.ROTATION_90:
break;
case Surface.ROTATION_180:
break;
case Surface.ROTATION_270:
break;
}


}

@Override
public void onDisplayRemoved(int displayId) {

}
};
DisplayManager displayManager = (DisplayManager) this.getSystemService(Context.DISPLAY_SERVICE);
displayManager.registerDisplayListener(mDisplayListener, new Handler());
}



onDisplayChanged함수는 여러번 반복하여 호출되기 때문에, 중복 작업을 방지하기 위해 최근의 방향을 저장해두고, 호출될 때마다 값을 비교하여 최초에 한번만 처리하도록 작성해야 합니다.



registerDisplayListener의 두번째 파라미터는 미리 만들어둔 Handler를 넘겨야 할 수도 있지만, 필자는 일단 위의 코드로 잘 동작했습니다.

mDisplayListener는 위에서는 지역변수로 만들었지만 실제는 Activity의 멤버변수로 빼두어야 합니다.




해제를 하자

함수명이 registerXXXXXXXXXX로 시작하는 걸로 봐서 unregisterXXXXXXXXXX도 있을 테고, 따라서 onDestroy에는 다음의 코드를 넣어줍니다.



DisplayManager displayManager = (DisplayManager) this.getSystemService(Context.DISPLAY_SERVICE);
displayManager.unregisterDisplayListener( mDisplayListener );






기타사항

Listener를 그냥 Activity로 지정하여 사용하는 편이 좋아 보입니다.


태블릿에서는 테스트를 해보지 않았지만, 기본 가로 방향이 "0도" 일 것이고, 모든 방향이 호출 될 것입니다. 태블릿지원시 두 부분을 구분하여 처리해야 합니다.




Replies
Reply Write