회전 처리Handling Rotation

이 항목에서는 Xamarin Android에서 장치 방향 변경을 처리 하는 방법을 설명 합니다. Android 리소스 시스템을 사용 하 여 특정 장치 방향에 대 한 리소스를 자동으로 로드 하는 방법 뿐만 아니라 방향 변경을 프로그래밍 방식으로 처리 하는 방법을 설명 합니다.This topic describes how to handle device orientation changes in Xamarin.Android. It covers how to work with the Android resource system to automatically load resources for a particular device orientation as well as how to programmatically handle orientation changes.

개요Overview

모바일 장치는 쉽게 회전 하므로 기본 제공 되는 회전은 모바일 Os의 표준 기능입니다.Because mobile devices are easily rotated, built-in rotation is a standard feature in mobile OSes. Android는 사용자 인터페이스가 XML로 선언적으로 만들어지거나 코드에서 프로그래밍 방식으로 생성 되는지에 관계 없이 응용 프로그램 내에서의 회전을 처리 하기 위한 정교한 프레임 워크를 제공 합니다.Android provides a sophisticated framework for dealing with rotation within applications, whether the user interface is created declaratively in XML or programmatically in code. 회전 된 장치에서 선언적 레이아웃 변경을 자동으로 처리 하는 경우 응용 프로그램은 Android 리소스 시스템과 긴밀 하 게 통합 되는 이점을 누릴 수 있습니다.When automatically handling declarative layout changes on a rotated device, an application can benefit from the tight integration with the Android resource system. 프로그래밍 레이아웃의 경우에는 변경 내용을 수동으로 처리 해야 합니다.For programmatic layout, changes must be handled manually. 이렇게 하면 런타임에 보다 세부적인 제어가 가능 하지만 개발자에 게 더 많은 작업이 수행 됩니다.This allows finer control at runtime, but at the expense of more work for the developer. 응용 프로그램은 활동 다시 시작을 옵트아웃 하 고 방향 변경을 수동으로 제어 하도록 선택할 수도 있습니다.An application can also choose to opt out of the Activity restart and take manual control of orientation changes.

이 가이드는 다음과 같은 방향 항목을 검사 합니다.This guide examines the following orientation topics:

  • 선언적 레이아웃 회전 – Android 리소스 시스템을 사용 하 여 특정 방향에 대 한 레이아웃 및 drawables을 로드 하는 방법을 비롯 하 여 방향 인식 응용 프로그램을 빌드하는 방법입니다.Declarative Layout Rotation – How to use the Android resource system to build orientation-aware applications, including how to load both layouts and drawables for particular orientations.

  • 프로그래밍 방식 레이아웃 회전 은 컨트롤을 프로그래밍 방식으로 추가 하는 방법 뿐만 아니라 수동으로 방향 변경을 처리 하는 방법 – 합니다.Programmatic Layout Rotation – How to add controls programmatically as well as how to handle orientation changes manually.

레이아웃을 사용 하 여 선언적으로 회전 처리Handling Rotation Declaratively with Layouts

명명 규칙을 따르는 폴더에 파일을 포함 하 여, 해당 방향이 변경 될 때 Android에서 적절 한 파일을 자동으로 로드 합니다.By including files in folders that follow naming conventions, Android automatically loads the appropriate files when the orientation changes. 여기에는에 대 한 지원이 포함 됩니다.This includes support for:

  • 각 방향에 대해 팽창 되는 레이아웃 파일을 지정 하는 – 레이아웃 리소스 입니다.Layout Resources – Specifying which layout files are inflated for each orientation.

  • 각 방향에 대해 로드 되는 drawables을 지정 하 – 그릴 수 있는 리소스 입니다.Drawable Resources – Specifying which drawables are loaded for each orientation.

리소스 레이아웃Layout Resources

기본적으로 리소스/레이아웃 폴더에 포함 된 Android XML (axml) 파일은 작업에 대 한 렌더링 보기에 사용 됩니다.By default, Android XML (AXML) files included in the Resources/layout folder are used for rendering views for an Activity. 이 폴더의 리소스는 가로 및 세로 방향으로 특별히 제공 되는 추가 레이아웃 리소스가 없는 경우 가로 및 세로 방향으로 모두 사용 됩니다.This folder's resources are used for both portrait and landscape orientation if no additional layout resources are provided specifically for landscape. 기본 프로젝트 템플릿에서 만든 프로젝트 구조를 고려 합니다.Consider the project structure created by the default project template:

기본 프로젝트 템플릿 구조Default project template structure

이 프로젝트는 리소스/레이아웃 폴더에 단일 Main. axml 파일을 만듭니다.This project creates a single Main.axml file in the Resources/layout folder. 활동의 OnCreate 메서드가 호출 되 면 아래 XML에 표시 된 것 처럼 단추를 선언 하는 늘어납니다에 정의 된 뷰를 만듭니다 .When the Activity's OnCreate method is called, it inflates the view defined in Main.axml, which declares a button as shown in the XML below:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
<Button  
  android:id="@+id/myButton"
  android:layout_width="fill_parent" 
  android:layout_height="wrap_content" 
  android:text="@string/hello"/>
</LinearLayout>

장치가 가로 방향으로 회전 되는 경우 작업의 OnCreate 메서드가 다시 호출 되 고, 아래 스크린샷에 표시 된 것 처럼 동일한 Main. axml 파일이 팽창 됩니다.If the device is rotated to landscape orientation, the Activity's OnCreate method is called again and the same Main.axml file is inflated, as shown in the screenshot below:

동일한 화면가로 방향으로Same screen but in landscape orientation

방향 별 레이아웃Orientation-Specific Layouts

레이아웃 폴더 (기본값은 세로이 고 layout-land폴더를 포함 하 여 레이아웃-포트 의 이름을 명시적으로 지정할 수도 있음) 외에도 응용 프로그램은 코드를 변경 하지 않고도 가로에서 필요한 뷰를 정의할 수 있습니다.In addition to the layout folder (which defaults to portrait and can also be explicitly named layout-port by including a folder named layout-land), an application can define the views it needs when in landscape without any code changes.

Main. axml 파일에 다음 XML이 포함 되어 있다고 가정 합니다.Suppose the Main.axml file contained the following XML:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <TextView
    android:text="This is portrait"
    android:layout_height="wrap_content"
    android:layout_width="fill_parent" />
</RelativeLayout>

추가 Main. axml 파일이 포함 된 레이아웃 육지 라는 폴더가 프로젝트에 추가 되 면, 않아서는 레이아웃을 가로 방향으로 지정 하면 이제 Android에서 새로 추가 된 기본. axml 을 로드 합니다.If a folder named layout-land that contains an additional Main.axml file is added to the project, inflating the layout when in landscape will now result in Android loading the newly added Main.axml. 다음 코드를 포함 하는 주. axml 파일의 가로 버전을 고려 합니다. 간단 하 게 하기 위해이 XML은 코드의 기본 세로 버전과 유사 하지만 TextView에서 다른 문자열을 사용 합니다.Consider the landscape version of the Main.axml file that contains the following code (for simplicity, this XML is similar to the default portrait version of the code, but uses a different string in the TextView):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <TextView
    android:text="This is landscape"
    android:layout_height="wrap_content"
    android:layout_width="fill_parent" />
</RelativeLayout>

이 코드를 실행 하 고 장치를 세로에서 가로 방향으로 회전 하면 다음과 같이 새로운 XML 로드를 보여 줍니다.Running this code and rotating the device from portrait to landscape demonstrates the new XML loading, as shown below:

세로 및 가로 스크린샷세로 모드 인쇄Portrait and landscape screenshots printing the portrait mode

그릴 때 리소스Drawable Resources

회전 하는 동안 Android는 그릴 수 있는 리소스를 레이아웃 리소스와 유사 하 게 처리 합니다.During rotation, Android treats drawable resources similarly to layout resources. 이 경우 시스템은 각각 리소스/그릴 때 및 리소스/그릴 때 발생 하는 폴더에서 drawables을 가져옵니다.In this case, the system gets the drawables from the Resources/drawable and Resources/drawable-land folders, respectively.

예를 들어, 프로젝트에는 Resources/그릴 수 있는 폴더에 원숭이 라는 이미지가 포함 되어 있습니다. 여기에서 그릴 수 있는 이미지는 다음과 같이 XML의 ImageView에서 참조 됩니다.For example, say the project includes an image named Monkey.png in the Resources/drawable folder, where the drawable is referenced from an ImageView in XML like this:

<ImageView
  android:layout_height="wrap_content"
  android:layout_width="wrap_content"
  android:src="@drawable/monkey"
  android:layout_centerVertical="true"
  android:layout_centerHorizontal="true" />

리소스/그릴수 있는 다른 버전의 원숭이 .png 가 포함 되어 있다고 가정 하겠습니다.Let's further assume that a different version of Monkey.png is included under Resources/drawable-land. 레이아웃 파일을 사용 하는 것과 마찬가지로 장치가 회전 될 때 아래와 같이 그릴 때 지정 된 방향으로 변경 됩니다.Just like with the layout files, when the device is rotated, the drawable changes for the given orientation, as shown below:

세로 및 가로 모드에 표시 되는 다른 버전의 원숭이를합니다.Different version of Monkey.png shown in portrait and landscape modes

프로그래밍 방식으로 회전 처리Handling Rotation Programmatically

코드에 레이아웃을 정의 하는 경우도 있습니다.Sometimes we define layouts in code. 이는 기술적 제한, 개발자 기본 설정 등 다양 한 이유로 발생할 수 있습니다. 프로그래밍 방식으로 컨트롤을 추가 하는 경우 응용 프로그램은 XML 리소스를 사용할 때 자동으로 처리 되는 장치 방향에 대해 수동으로 계정을 만들어야 합니다.This can happen for a variety of reasons, including technical limitations, developer preference, etc. When we add controls programmatically, an application must manually account for device orientation, which is handled automatically when we use XML resources.

코드에 컨트롤 추가Adding Controls in Code

응용 프로그램에서 프로그래밍 방식으로 컨트롤을 추가 하려면 다음 단계를 수행 해야 합니다.To add controls programmatically, an application needs to perform the following steps:

  • 레이아웃을 만듭니다.Create a layout.
  • 레이아웃 매개 변수를 설정 합니다.Set layout parameters.
  • 컨트롤을 만듭니다.Create controls.
  • 컨트롤 레이아웃 매개 변수를 설정 합니다.Set control layout parameters.
  • 레이아웃에 컨트롤을 추가 합니다.Add controls to the layout.
  • 레이아웃을 콘텐츠 뷰로 설정 합니다.Set the layout as the content view.

예를 들어 다음 코드와 같이 RelativeLayout에 추가 된 단일 TextView 컨트롤로 구성 된 사용자 인터페이스를 살펴보겠습니다.For example, consider a user interface consisting of a single TextView control added to a RelativeLayout, as shown in the following code.

protected override void OnCreate (Bundle bundle)
{
  base.OnCreate (bundle);
                        
  // create a layout
  var rl = new RelativeLayout (this);

  // set layout parameters
  var layoutParams = new RelativeLayout.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.FillParent);
  rl.LayoutParameters = layoutParams;
        
  // create TextView control
  var tv = new TextView (this);

  // set TextView's LayoutParameters
  tv.LayoutParameters = layoutParams;
  tv.Text = "Programmatic layout";

  // add TextView to the layout
  rl.AddView (tv);
        
  // set the layout as the content view
  SetContentView (rl);
}

이 코드는 RelativeLayout 클래스의 인스턴스를 만들고 해당 LayoutParameters 속성을 설정 합니다.This code creates an instance of a RelativeLayout class and sets its LayoutParameters property. LayoutParams 클래스는 다시 사용 가능한 방식으로 컨트롤의 위치를 지정 하는 방법을 캡슐화 하는 Android의 방법입니다.The LayoutParams class is Android's way of encapsulating how controls are positioned in a reusable way. 레이아웃의 인스턴스를 만든 후에는 컨트롤을 만들어 추가할 수 있습니다.Once an instance of a layout is created, controls can be created and added to it. 컨트롤에는이 예제에서 TextView 같은 LayoutParameters포함 됩니다.Controls also have LayoutParameters, such as the TextView in this example. TextView 생성 된 후 RelativeLayout에 추가 하 고 RelativeLayout를 콘텐츠 뷰로 설정 하면 다음과 같이 응용 프로그램에 TextView 표시 됩니다.After the TextView is created, adding it to the RelativeLayout and setting the RelativeLayout as the content view results in the application displaying the TextView as shown:

세로 및 가로 모드에서 표시 되는증가 카운터 단추Increment counter button shown in both portrait and landscape modes

코드의 방향 감지Detecting Orientation in Code

응용 프로그램에서 OnCreate가 호출 될 때 각 방향에 대해 다른 사용자 인터페이스를 로드 하려고 시도 하는 경우 (장치가 회전 될 때마다 발생 함) 방향을 검색 한 다음 원하는 사용자 인터페이스 코드를 로드 해야 합니다.If an application tries to load a different user interface for each orientation when OnCreate is called (this will happen each time a device is rotated), it must detect the orientation, and then load the desired user interface code. Android에는 아래와 같이 WindowManager.DefaultDisplay.Rotation 속성을 통해 현재 장치 회전을 결정 하는 데 사용할 수 있는 WindowManager이라는 클래스가 있습니다.Android has a class called the WindowManager, which can be used to determine the current device rotation via the WindowManager.DefaultDisplay.Rotation property, as shown below:

protected override void OnCreate (Bundle bundle)
{
  base.OnCreate (bundle);
                        
  // create a layout
  var rl = new RelativeLayout (this);

  // set layout parameters
  var layoutParams = new RelativeLayout.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.FillParent);
  rl.LayoutParameters = layoutParams;
                        
  // get the initial orientation
  var surfaceOrientation = WindowManager.DefaultDisplay.Rotation;
  // create layout based upon orientation
  RelativeLayout.LayoutParams tvLayoutParams;
                
  if (surfaceOrientation == SurfaceOrientation.Rotation0 || surfaceOrientation == SurfaceOrientation.Rotation180) {
    tvLayoutParams = new RelativeLayout.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
  } else {
    tvLayoutParams = new RelativeLayout.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
    tvLayoutParams.LeftMargin = 100;
    tvLayoutParams.TopMargin = 100;
  }
                        
  // create TextView control
  var tv = new TextView (this);
  tv.LayoutParameters = tvLayoutParams;
  tv.Text = "Programmatic layout";
        
  // add TextView to the layout
  rl.AddView (tv);
        
  // set the layout as the content view
  SetContentView (rl);
}

이 코드 TextView는 다음과 같이 화면 왼쪽 위에서 100 픽셀의 위치를 지정 하 여 자동으로 새 레이아웃에 애니메이션을 적용 합니다.This code sets the TextView to be positioned 100 pixels from the top left of the screen, automatically animating to the new layout, when rotated to landscape, as shown here:

뷰 상태는 세로 및 가로 모드에서 유지 됩니다.View state is preserved across portrait and landscape modes

활동 다시 시작 방지Preventing Activity Restart

응용 프로그램은 OnCreate의 모든 항목을 처리 하는 것 외에도 다음과 같이 ActivityAttributeConfigurationChanges를 설정 하 여 작업이 다시 시작 되지 않도록 할 수 있습니다.In addition to handling everything in OnCreate, an application can also prevent an Activity from being restarted when the orientation changes by setting ConfigurationChanges in the ActivityAttribute as follows:

[Activity (Label = "CodeLayoutActivity", ConfigurationChanges=Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize)]

이제 장치가 회전 될 때 활동이 다시 시작 되지 않습니다.Now when the device is rotated, the Activity is not restarted. 이 경우 방향 변경을 수동으로 처리 하기 위해 활동은 OnConfigurationChanged 메서드를 재정의 하 고 아래 활동의 새 구현과 같이 전달 되는 Configuration 개체에서 방향을 결정할 수 있습니다.In order to manually handle the orientation change in this case, an Activity can override the OnConfigurationChanged method and determine the orientation from the Configuration object that is passed in, as in the new implementation of the Activity below:

[Activity (Label = "CodeLayoutActivity", ConfigurationChanges=Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize)]
public class CodeLayoutActivity : Activity
{
  TextView _tv;
  RelativeLayout.LayoutParams _layoutParamsPortrait;
  RelativeLayout.LayoutParams _layoutParamsLandscape;
                
  protected override void OnCreate (Bundle bundle)
  {
    // create a layout
    // set layout parameters
    // get the initial orientation

    // create portrait and landscape layout for the TextView
    _layoutParamsPortrait = new RelativeLayout.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
                
    _layoutParamsLandscape = new RelativeLayout.LayoutParams (ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.WrapContent);
    _layoutParamsLandscape.LeftMargin = 100;
    _layoutParamsLandscape.TopMargin = 100;
                        
    _tv = new TextView (this);
                        
    if (surfaceOrientation == SurfaceOrientation.Rotation0 || surfaceOrientation == SurfaceOrientation.Rotation180) {
      _tv.LayoutParameters = _layoutParamsPortrait;
    } else {
      _tv.LayoutParameters = _layoutParamsLandscape;
    }
                        
    _tv.Text = "Programmatic layout";
    rl.AddView (_tv);
    SetContentView (rl);
  }
                
  public override void OnConfigurationChanged (Android.Content.Res.Configuration newConfig)
  {
    base.OnConfigurationChanged (newConfig);
                        
    if (newConfig.Orientation == Android.Content.Res.Orientation.Portrait) {
      _tv.LayoutParameters = _layoutParamsPortrait;
      _tv.Text = "Changed to portrait";
    } else if (newConfig.Orientation == Android.Content.Res.Orientation.Landscape) {
      _tv.LayoutParameters = _layoutParamsLandscape;
      _tv.Text = "Changed to landscape";
    }
  }
}

여기서 TextView's 레이아웃 매개 변수는 가로 및 세로 모두에 대해 초기화 됩니다.Here the TextView's layout parameters are initialized for both landscape and portrait. 방향이 변경 될 때 활동이 다시 생성 되지 않으므로 클래스 변수에는 TextView 자체와 함께 매개 변수가 포함 됩니다.Class variables hold the parameters, along with the TextView itself, since the Activity will not be re-created when orientation changes. 코드는 여전히 OnCreatesurfaceOrientartion를 사용 하 여 TextView의 초기 레이아웃을 설정 합니다.The code still uses the surfaceOrientartion in OnCreate to set the initial layout for the TextView. 이후에는 OnConfigurationChanged 모든 후속 레이아웃 변경 내용을 처리 합니다.After that, OnConfigurationChanged handles all subsequent layout changes.

응용 프로그램을 실행할 때 Android는 장치 회전이 발생 함에 따라 사용자 인터페이스 변경 사항을 로드 하 고 작업을 다시 시작 하지 않습니다.When we run the application, Android loads the user interface changes as device rotation occurs, and does not restart the Activity.

선언 레이아웃에 대 한 작업 다시 시작 방지Preventing Activity Restart for Declarative Layouts

XML에서 레이아웃을 정의 하는 경우 장치 회전으로 인 한 작업 다시 시작을 방지할 수도 있습니다.Activity restarts caused by device rotation can also be prevented if we define the layout in XML. 예를 들어, 성능상의 이유로 작업을 다시 시작 하는 것을 방지 하려는 경우이 방법을 사용할 수 있으며, 다른 방향에 대 한 새 리소스를 로드할 필요가 없습니다.For example, we can use this approach if we want to prevent an Activity restart (for performance reasons, perhaps) and we don't need to load new resources for different orientations.

이렇게 하려면 프로그래밍 방식 레이아웃에 사용 하는 것과 동일한 절차를 따릅니다.To do this, we follow the same procedure that we use with a programmatic layout. 이전 CodeLayoutActivity에서 했던 것 처럼 ActivityAttributeConfigurationChanges를 설정 하면 됩니다.Simply set ConfigurationChanges in the ActivityAttribute, as we did in the CodeLayoutActivity earlier. 방향 변경을 위해 실행 해야 하는 모든 코드는 OnConfigurationChanged 메서드에서 다시 구현할 수 있습니다.Any code that does need to run for the orientation change can again be implemented in the OnConfigurationChanged method.

방향 변경 중 상태 유지 관리Maintaining State During Orientation Changes

회전을 선언적으로 또는 프로그래밍 방식으로 처리 하는지에 관계 없이 모든 Android 응용 프로그램은 장치 방향이 변경 될 때 상태를 관리 하기 위해 동일한 기술을 구현 해야 합니다.Whether handling rotation declaratively or programmatically, all Android applications should implement the same techniques for managing state when device orientation changes. Android 장치를 회전할 때 시스템이 실행 중인 작업을 다시 시작 하므로 상태 관리가 중요 합니다.Managing state is important because the system restarts a running Activity when an Android device is rotated. Android는 특정 방향에 맞게 특별히 디자인 된 레이아웃 및 drawables과 같은 대체 리소스를 쉽게 로드할 수 있도록 합니다.Android does this to make it easy to load alternate resources, such as layouts and drawables that are designed specifically for a particular orientation. 작업을 다시 시작 하면 로컬 클래스 변수에 저장 했을 수 있는 모든 일시적 상태가 손실 됩니다.When it restarts, the Activity loses any transient state it may have stored in local class variables. 따라서 활동이 상태 기반 인 경우 응용 프로그램 수준에서 상태를 유지 해야 합니다.Therefore, if an Activity is state reliant, it must persist its state at the application level. 응용 프로그램은 방향 변경에 대해 유지 하려는 응용 프로그램 상태를 저장 하 고 복원 하는 것을 처리 해야 합니다.An application needs to handle saving and restoring any application state that it wants to preserve across orientation changes.

Android에서 상태를 유지 하는 방법에 대 한 자세한 내용은 활동 수명 주기 가이드를 참조 하세요.For more information on persisting state in Android, refer to the Activity Lifecycle guide.

요약Summary

이 문서에서는 Android의 기본 제공 기능을 사용 하 여 회전 작업을 수행 하는 방법을 살펴보았습니다.This article covered how to use Android's built-in capabilities to work with rotation. 먼저, Android 리소스 시스템을 사용 하 여 방향 인식 응용 프로그램을 만드는 방법을 설명 했습니다.First, it explained how to use the Android resource system to create orientation aware applications. 그런 다음 코드에 컨트롤을 추가 하는 방법 뿐만 아니라 방향 변경을 수동으로 처리 하는 방법을 제공 했습니다.Then it presented how to add controls in code as well as how to handle orientation changes manually.