The Android Developer Challenge is back! Submit your idea before December 2.

유연한 UI 빌드

다양한 화면 크기를 지원하도록 애플리케이션을 디자인할 경우 프래그먼트를 다양한 레이아웃 구성에서 다시 사용하여 사용 가능한 화면 공간에 따라 사용자 환경을 최적화할 수 있습니다.

예를 들어 핸드셋 기기인 경우 단일 창 사용자 인터페이스에 프래그먼트를 한 번에 하나씩만 표시하는 것이 적합할 수 있습니다. 반대로, 화면 너비가 큰 태블릿에서는 프래그먼트를 나란히 설정하여 사용자에게 더 많은 정보를 표시할 수 있습니다.

그림 1. 서로 다른 화면 크기에서 같은 활동이 다른 구성으로 표시된 두 프래그먼트. 큰 화면에서는 두 프래그먼트를 모두 나란히 표시하지만 핸드셋 기기에서는 프래그먼트가 한 번에 하나씩 표시되므로 사용자가 탐색할 때 프래그먼트가 서로 교체되어야 합니다.

FragmentManager 클래스에서는 동적인 환경을 만들기 위해 런타임 시 활동에 관해 프래그먼트를 추가, 삭제, 교체할 수 있는 메서드를 제공합니다.

프래그먼트 구현에 관한 자세한 정보는 다음 리소스를 참조하세요.

런타임에 액티비티에 프래그먼트 추가

<fragment> 요소를 사용하는 이전 과정의 내용대로 활동에 관한 프래그먼트를 레이아웃 파일에서 정의하는 대신 활동 런타임 중에 프래그먼트를 활동에 추가할 수 있습니다. 이 작업은 활동 사용 기간 프래그먼트를 변경하려는 경우에 필요합니다.

프래그먼트 추가 또는 삭제와 같은 트랜잭션을 실행하려면 FragmentManager를 사용하여 FragmentTransaction을 만들어서 다른 프래그먼트 트랜잭션을 추가, 삭제, 교체, 실행하는 API를 제공해야 합니다.

활동에서 프래그먼트를 삭제하거나 교체할 수 있는 경우 활동의 onCreate() 메서드 중에 초기 프래그먼트를 활동에 추가해야 합니다.

프래그먼트를 처리할 때 특히 런타임에 프래그먼트를 추가할 때 중요한 규칙은 프래그먼트를 삽입할 수 있는 컨테이너 View가 활동 레이아웃에 포함되어야 한다는 것입니다.

이전 과정에 나와 있는 대로 프래그먼트를 한 번에 하나씩만 표시하는 레이아웃 대신 다음 레이아웃을 사용할 수 있습니다. 한 프래그먼트를 다른 프래그먼트로 교체하기 위해 활동 레이아웃에는 프래그먼트 컨테이너 역할을 하는 빈 FrameLayout이 포함됩니다.

파일 이름은 이전 과정의 레이아웃 파일과 동일하지만, 레이아웃 디렉터리에 large 한정자가 없기 때문에 이 레이아웃은 기기 화면이 동시에 두 프래그먼트에 맞지 않아서 기기 화면이 크지 않고 작은 경우 사용됩니다.

res/layout/news_articles.xml:

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    

작업 내부에서 getSupportFragmentManager()를 호출하고 지원 라이브러리 API를 사용하여 FragmentManager를 가져옵니다. 그런 다음 beginTransaction()을 호출하여 FragmentTransaction을 만들고 add()를 호출하여 프래그먼트를 추가합니다.

동일한 FragmentTransaction을 사용하여 활동의 여러 프래그먼트 트랜잭션을 실행할 수 있습니다. 변경할 준비가 되면 commit()를 호출해야 합니다.

예를 들어 다음은 이전 레이아웃에 프래그먼트를 추가하는 방법입니다.

Kotlin

    import android.os.Bundle
    import android.support.v4.app.FragmentActivity

    class MainActivity : FragmentActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.news_articles)

            // Check that the activity is using the layout version with
            // the fragment_container FrameLayout
            if (findViewById(R.id.fragment_container) != null) {

                // However, if we're being restored from a previous state,
                // then we don't need to do anything and should return or else
                // we could end up with overlapping fragments.
                if (savedInstanceState != null) {
                    return;
                }

                // Create a new Fragment to be placed in the activity layout
                val firstFragment = HeadlinesFragment()

                // In case this activity was started with special instructions from an
                // Intent, pass the Intent's extras to the fragment as arguments
                firstFragment.arguments = intent.extras

                // Add the fragment to the 'fragment_container' FrameLayout
                supportFragmentManager.beginTransaction()
                        .add(R.id.fragment_container, firstFragment).commit()
            }
        }
    }
    

자바

    import android.os.Bundle;
    import android.support.v4.app.FragmentActivity;

    public class MainActivity extends FragmentActivity {
        @Override
        public void onCreate(Bundle savedInstanceState?) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.news_articles);

            // Check that the activity is using the layout version with
            // the fragment_container FrameLayout
            if (findViewById(R.id.fragment_container) != null) {

                // However, if we're being restored from a previous state,
                // then we don't need to do anything and should return or else
                // we could end up with overlapping fragments.
                if (savedInstanceState != null) {
                    return;
                }

                // Create a new Fragment to be placed in the activity layout
                HeadlinesFragment firstFragment = new HeadlinesFragment();

                // In case this activity was started with special instructions from an
                // Intent, pass the Intent's extras to the fragment as arguments
                firstFragment.setArguments(getIntent().getExtras());

                // Add the fragment to the 'fragment_container' FrameLayout
                getSupportFragmentManager().beginTransaction()
                        .add(R.id.fragment_container, firstFragment).commit();
            }
        }
    }
    

<fragment> 요소를 사용하여 활동 레이아웃에서 정의하는 대신 런타임에 프래그먼트를 FrameLayout 컨테이너에 추가했기 때문에 활동이 프래그먼트를 삭제하고 다른 프래그먼트로 교체할 수 있습니다.

한 프래그먼트를 다른 프래그먼트로 교체

프래그먼트를 교체하는 절차는 추가하는 절차와 비슷하지만 add()가 아닌 replace() 메서드가 필요합니다.

프래그먼트 교체 또는 삭제와 같은 프래그먼트 트랜잭션을 실행할 때는 사용자가 뒤로 탐색하여 변경을 '실행취소'하는 것이 적합한 경우가 많습니다. 사용자가 프래그먼트 트랜잭션을 뒤로 탐색할 수 있으려면 FragmentTransaction을 커밋하기 전에 addToBackStack()을 호출해야 합니다.

참고: 프래그먼트를 삭제하거나 교체하고 트랜잭션을 백 스택에 추가하면 삭제된 프래그먼트가 중지됩니다(폐기되지 않음). 사용자가 뒤로 탐색하여 프래그먼트를 복원하는 경우 프래그먼트가 다시 시작됩니다. 트랜잭션을 백 스택에 추가하지 않으면 프래그먼트를 삭제하거나 교체하는 경우 프래그먼트가 폐기됩니다.

다른 프래그먼트와의 교체 예:

Kotlin

    // Create fragment and give it an argument specifying the article it should show
    val newFragment = ArticleFragment()
    Bundle args = Bundle()
    args.putInt(ArticleFragment.ARG_POSITION, position)
    newFragment.arguments = args

    val transaction = supportFragmentManager.beginTransaction().apply {
      // Replace whatever is in the fragment_container view with this fragment,
      // and add the transaction to the back stack so the user can navigate back
      replace(R.id.fragment_container, newFragment)
      addToBackStack(null)
    }

    // Commit the transaction
    transaction.commit();
    

자바

    // Create fragment and give it an argument specifying the article it should show
    ArticleFragment newFragment = new ArticleFragment();
    Bundle args = new Bundle();
    args.putInt(ArticleFragment.ARG_POSITION, position);
    newFragment.setArguments(args);

    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

    // Replace whatever is in the fragment_container view with this fragment,
    // and add the transaction to the back stack so the user can navigate back
    transaction.replace(R.id.fragment_container, newFragment);
    transaction.addToBackStack(null);

    // Commit the transaction
    transaction.commit();
    

addToBackStack() 메서드는 트랜잭션의 고유한 이름을 지정하는 선택적 문자열 매개변수를 사용합니다. 이름은 FragmentManager.BackStackEntry API를 사용하여 고급 프래그먼트 작업을 실행할 계획인 경우에만 필요합니다.