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());
}

위코드 다운로드


detectrotate.java




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