NavigationUI로 UI 구성요소 업데이트

탐색 아키텍처 구성요소에는 NavigationUI 클래스가 포함되어 있습니다. 이 클래스에는 상단 앱 바, 탐색 창, 하단 탐색으로 탐색을 관리하는 정적 메서드가 있습니다.

탐색 이벤트 수신 대기

NavController와의 상호작용은 대상 간 탐색을 위한 기본 방법입니다. NavControllerNavHost의 콘텐츠를 새로운 대상으로 대체합니다. 대부분의 경우 상단 앱 바 또는 BottomNavigationBar 같은 기타 영구 탐색 컨트롤 등의 UI 요소는 NavHost 외부에 존재하며 대상 간을 탐색할 때 업데이트되어야 합니다.

NavController는 의 현재 대상 또는 그 인수가 변경될 때 호출되는 OnDestinationChangedListener 인터페이스를 제공합니다. 새 리스너는 addOnDestinationChangedListener() 메서드를 통해 등록될 수 있습니다. addOnDestinationChangedListener()를 호출할 때 현재 대상이 있으면 그 대상을 즉시 리스너로 보냅니다.

NavigationUIOnDestinationChangedListener를 사용하여 공통 UI 구성요소가 탐색을 인식하도록 합니다. 하지만 OnDestinationChangedListener를 자체적으로 사용하여 모든 맞춤 UI 또는 비즈니스 로직에서 탐색 이벤트를 인식하도록 할 수도 있습니다.

예를 들어 앱의 일부 영역에서는 표시하고 다른 영역에서는 숨기려는 공통 UI 요소가 있을 수 있습니다. 다음 예에서와 같이 자체 OnDestinationChangedListener를 사용하면 타겟 대상에 따라 이러한 UI 요소를 선택적으로 표시하거나 숨길 수 있습니다.

Kotlin

    navController.addOnDestinationChangedListener { _, destination, _ ->
       if(destination.id == R.id.full_screen_destination) {
           toolbar.visibility = View.GONE
           bottomNavigationView.visibility = View.GONE
       } else {
           toolbar.visibility = View.VISIBLE
           bottomNavigationView.visibility = View.VISIBLE
       }
    }
    

자바

    navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
       @Override
       public void onDestinationChanged(@NonNull NavController controller,
               @NonNull NavDestination destination, @Nullable Bundle arguments) {
           if(destination.getId() == R.id.full_screen_destination) {
               toolbar.setVisibility(View.GONE);
               bottomNavigationView.setVisibility(View.GONE);
           } else {
               toolbar.setVisibility(View.VISIBLE);
               bottomNavigationView.setVisibility(View.VISIBLE);
           }
       }
    });
    

상단 앱 바

상단 앱 바는 현재 화면의 정보와 작업을 표시하기 위해 앱의 상단을 따라 일관된 위치를 제공합니다.

NavigationUI에는 사용자가 앱을 탐색할 때 상단 앱 바의 콘텐츠를 자동으로 업데이트하는 메서드가 포함되어 있습니다. 예를 들어 는 탐색 그래프의 대상 라벨을 사용하여 상단 앱 바의 제목을 최신 상태로 유지합니다.

아래에 설명된 상단 앱 바 메서드와 NavigationUI을 사용하면 라벨의 {argName} 형식을 사용하여 대상에 제공된 인수에서 대상에 첨부하는 라벨을 자동으로 채울 수 있습니다.

NavigationUI는 다음과 같은 상단 앱 바 유형을 지원합니다.

AppBarConfiguration

NavigationUIAppBarConfiguration 객체를 사용하여 앱 표시 영역의 왼쪽 상단에 있는 탐색 버튼의 동작을 관리합니다. 기본적으로 탐색 버튼은 사용자가 탐색 그래프의 최상위 대상에 있을 때 숨겨지고 그 외 다른 대상에서는 위로 버튼으로 표시됩니다.

탐색 그래프의 시작 위치를 최상위 대상만으로 사용하려면 아래에서와 같이 AppBarConfiguration 객체를 만든 다음 대응하는 탐색 그래프에 전달합니다.

Kotlin

    val appBarConfiguration = AppBarConfiguration(navController.graph)
    

자바

    AppBarConfiguration appBarConfiguration =
            new AppBarConfiguration.Builder(navController.getGraph()).build();
    

최상위 대상으로 간주되는 대상을 맞춤설정하려면 아래에서와 같이 대상 ID 집합을 생성자에 전달합니다.

Kotlin

    val appBarConfiguration = AppBarConfiguration(setOf(R.id.main, R.id.android))
    

자바

    AppBarConfiguration appBarConfiguration =
            new AppBarConfiguration.Builder(R.id.main, R.id.android).build();
    

툴바 만들기

NavigationUI로 툴바를 만들려면 아래에서와 같이 먼저 기본 활동에 바를 정의합니다.

    <LinearLayout>
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar" />
        <fragment
            android:id="@+id/nav_host_fragment"
            ... />
        ...
    </LinearLayout>
    

그런 다음 아래에서와 같이 기본 활동의 onCreate() 메서드에서 setupWithNavController()를 호출합니다.

Kotlin

    override fun onCreate(savedInstanceState: Bundle?) {
        setContentView(R.layout.activity_main)

        ...

        val navController = findNavController(R.id.nav_host_fragment)
        val appBarConfiguration = AppBarConfiguration(navController.graph)
        findViewById<Toolbar>(R.id.toolbar)
            .setupWithNavController(navController, appBarConfiguration)
    }
    

자바

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.activity_main);

        ...

        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        AppBarConfiguration appBarConfiguration =
                new AppBarConfiguration.Builder(navController.getGraph()).build();
        Toolbar toolbar = findViewById(R.id.toolbar);
        NavigationUI.setupWithNavController(toolbar, navController);
    }
    

CollapsingToolbarLayout 포함

툴바로 CollapsingToolbarLayout을 포함하려면 아래에서와 같이 먼저 기본 활동에 툴바와 주변 레이아웃을 정의합니다.

    <LinearLayout>
        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="@dimen/tall_toolbar_height">

            <android.support.design.widget.CollapsingToolbarLayout
                android:id="@+id/collapsing_toolbar_layout"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:contentScrim="?attr/colorPrimary"
                app:expandedTitleGravity="top"
                app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">

                <android.support.v7.widget.Toolbar
                    android:id="@+id/toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    app:layout_collapseMode="pin"/>
            </android.support.design.widget.CollapsingToolbarLayout>
        </android.support.design.widget.AppBarLayout>

        <fragment
            android:id="@+id/nav_host_fragment"
            ... />
        ...
    </LinearLayout>
    

그런 다음 아래에서와 같이 기본 활동의 onCreate 메서드에서 setupWithNavController()를 호출합니다.

Kotlin

    override fun onCreate(savedInstanceState: Bundle?) {
        setContentView(R.layout.activity_main)

        ...

        val layout = findViewById<CollapsingToolbarLayout>(R.id.collapsing_toolbar_layout)
        val toolbar = findViewById<Toolbar>(R.id.toolbar)
        val navController = findNavController(R.id.nav_host_fragment)
        val appBarConfiguration = AppBarConfiguration(navController.graph)
        layout.setupWithNavController(toolbar, navController, appBarConfiguration)
    }
    

자바

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.activity_main);

        ...

        CollapsingToolbarLayout layout = findViewById(R.id.collapsing_toolbar_layout);
        Toolbar toolbar = findViewById(R.id.toolbar);
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        AppBarConfiguration appBarConfiguration =
                new AppBarConfiguration.Builder(navController.getGraph()).build();
        NavigationUI.setupWithNavController(layout, toolbar, navController, appBarConfiguration);
    }
    

작업 모음

기본 작업 모음에 탐색 지원을 추가하려면 아래에서와 같이 기본 활동의 onCreate() 메서드에서 setupActionBarWithNavController()를 호출합니다. AppBarConfigurationonSupportNavigateUp()을 재정의할 때도 사용하므로 onCreate() 외부에 선언해야 합니다.

Kotlin

    private lateinit var appBarConfiguration: AppBarConfiguration

    ...

    override fun onCreate(savedInstanceState: Bundle?) {
        ...

        val navController = findNavController(R.id.nav_host_fragment)
        appBarConfiguration = AppBarConfiguration(navController.graph)
        setupActionBarWithNavController(navController, appBarConfiguration)
    }
    

자바

    AppBarConfiguration appBarConfiguration;

    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...

        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();
        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
    }
    

그런 다음 onSupportNavigateUp()을 재정의하여 위로 탐색을 처리합니다.

Kotlin

    override fun onSupportNavigateUp(): Boolean {
        val navController = findNavController(R.id.nav_host_fragment)
        return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
    }
    

자바

    @Override
    public boolean onSupportNavigateUp() {
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        return NavigationUI.navigateUp(navController, appBarConfiguration)
                || super.onSupportNavigateUp();
    }
    

대상을 메뉴 항목에 연결

NavigationUI는 대상을 메뉴 기반 UI 구성요소에 연결하기 위한 도우미도 제공합니다. NavigationUI에는 연결된 대상을 호스팅하는 NavController와 함께 MenuItem을 받는 도우미 메서드 onNavDestinationSelected()가 포함되어 있습니다. MenuItemid가 대상의 id와 일치하면 NavController가 그 대상으로 이동할 수 있습니다.

예를 들어 아래의 XML 스니펫에서는 공통 id, details_page_fragment가 있는 메뉴 항목과 대상을 정의합니다.

    <?xml version="1.0" encoding="utf-8"?>
    <navigation xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:android="http://schemas.android.com/apk/res/android"
        ... >

        ...

        <fragment android:id="@+id/details_page_fragment"
             android:label="@string/details"
             android:name="com.example.android.myapp.DetailsFragment" />
    </navigation>
    
    <menu xmlns:android="http://schemas.android.com/apk/res/android">

        ...

        <item
            android:id="@id/details_page_fragment"
            android:icon="@drawable/ic_details"
            android:title="@string/details" />
    </menu>
    

예를 들어 아래에서와 같이 활동의 onCreateOptionsMenu()를 통해 메뉴가 추가된 경우 onNavDestinationSelected()를 호출할 활동의 onOptionsItemSelected()를 재정의하여 메뉴 항목을 대상과 연결할 수 있습니다.

Kotlin

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        val navController = findNavController(R.id.nav_host_fragment)
        return item.onNavDestinationSelected(navController) || super.onOptionsItemSelected(item)
    }
    

자바

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        return NavigationUI.onNavDestinationSelected(item, navController)
                || super.onOptionsItemSelected(item);
    }
    

이제 사용자가 details_page_fragment 메뉴 항목을 클릭하면 앱이 자동으로 id가 동일한 해당하는 대상으로 이동합니다.

탐색 창 추가

탐색 창은 앱의 기본 탐색 메뉴를 표시하는 UI 패널입니다. 사용자가 앱 바에서 창 아이콘 을 터치하거나 화면의 왼쪽 가장자리에서 손가락을 스와이프하면 창이 표시됩니다.

창 아이콘은 DrawerLayout을 사용하는 모든 최상위 대상에 표시됩니다. 최상위 대상은 앱의 루트 수준 대상이며 앱 바에 위로 버튼을 표시하지 않습니다.

탐색 창을 추가하려면 먼저 DrawerLayout을 루트 뷰로 선언합니다. DrawerLayout 내부에 기본 UI 콘텐츠의 레이아웃과 탐색 창의 콘텐츠가 포함된 다른 뷰를 추가합니다.

예를 들어 다음 레이아웃은 2개의 하위 뷰(기본 콘텐츠를 포함하기 위한 NavHostFragment와 탐색 창의 콘텐츠를 위한 NavigationView)가 있는 DrawerLayout을 사용합니다.

<?xml version="1.0" encoding="utf-8"?>
    <!-- Use DrawerLayout as root container for activity -->
    <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true">

        <!-- Layout to contain contents of main body of screen (drawer will slide over this) -->
        <fragment
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:id="@+id/nav_host_fragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:defaultNavHost="true"
            app:navGraph="@navigation/nav_graph" />

        <!-- Container for contents of drawer - use NavigationView to make configuration easier -->
        <android.support.design.widget.NavigationView
            android:id="@+id/nav_view"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:fitsSystemWindows="true" />

    </android.support.v4.widget.DrawerLayout>
    

그런 다음 아래에 표시된 것처럼 DrawerLayoutAppBarConfiguration에 전달하여 탐색 그래프에 연결합니다.

Kotlin

    val appBarConfiguration = AppBarConfiguration(navController.graph, drawerLayout)
    

자바

    AppBarConfiguration appBarConfiguration =
            new AppBarConfiguration.Builder(navController.getGraph())
                .setDrawerLayout(drawerLayout)
                .build();
    

그런 다음 아래에서와 같이 기본 활동 클래스에서 기본 활동의 onCreate() 메서드에서 setupWithNavController()를 호출합니다.

Kotlin

    override fun onCreate(savedInstanceState: Bundle?) {
        setContentView(R.layout.activity_main)

        ...

        val navController = findNavController(R.id.nav_host_fragment)
        findViewById<NavigationView>(R.id.nav_view)
            .setupWithNavController(navController)
    }
    

자바

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.activity_main);

        ...

        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        NavigationView navView = findViewById(R.id.nav_view);
        NavigationUI.setupWithNavController(navView, navController);
    }
    

하단 탐색

NavigationUI도 하단 탐색을 처리할 수 있습니다. 사용자가 메뉴 항목을 선택하면 NavController에서 onNavDestinationSelected()를 호출하고 하단 탐색 메뉴에서 선택된 항목을 자동으로 업데이트합니다.

앱에서 하단 탐색 메뉴를 만들려면 먼저 아래에서와 같이 기본 활동에 바를 정의합니다.

    <LinearLayout>
        ...
        <fragment
            android:id="@+id/nav_host_fragment"
            ... />
        <android.support.design.widget.BottomNavigationView
            android:id="@+id/bottom_nav"
            app:menu="@menu/menu_bottom_nav" />
    </LinearLayout>
    

그런 다음 아래에서와 같이 기본 활동 클래스에서 기본 활동의 onCreate() 메서드에서 setupWithNavController()를 호출합니다.

Kotlin

    override fun onCreate(savedInstanceState: Bundle?) {
        setContentView(R.layout.activity_main)

        ...

        val navController = findNavController(R.id.nav_host_fragment)
        findViewById<BottomNavigationView>(R.id.bottom_nav)
            .setupWithNavController(navController)
    }
    

자바

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.activity_main);

        ...

        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        BottomNavigationView bottomNav = findViewById(R.id.bottom_nav);
        NavigationUI.setupWithNavController(bottomNav, navController);
    }
    

하단 탐색이 포함된 종합적인 예는 GitHub의 Android 아키텍처 구성요소 고급 탐색 샘플 을 참조하세요.

추가 리소스

탐색에 관한 자세한 내용은 다음 추가 리소스를 참조하세요.

샘플

Codelab

블로그 게시물

동영상