유연한 UI 구축

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

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

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

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

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

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

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

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

활동에서 프래그먼트를 삭제하거나 교체할 수 있는 경우 활동의 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를 사용하여 고급 프래그먼트 작업을 수행할 계획인 경우에만 필요합니다.