Cập nhật thành phần giao diện người dùng bằng NavigationUI | Android Developers

Thành phần Điều hướng (Navigation) bao gồm một lớp NavigationUI. Lớp này chứa các phương thức tĩnh quản lý cách điều hướng bằng thanh ứng dụng trên cùng, ngăn điều hướng và trình đơn điều hướng ở dưới cùng.

Thanh ứng dụng trên cùng

Thanh ứng dụng trên cùng (top app bar) cung cấp một vị trí nhất quán theo đầu ứng dụng để hiển thị thông tin và các hành động trên màn hình hiện tại.

màn hình cho thấy một thanh ứng dụng trên cùng
Hình 1. Một màn hình cho thấy một thanh ứng dụng trên cùng.

NavigationUI chứa các phương thức tự động cập nhật nội dung trên thanh ứng dụng trên cùng khi người dùng di chuyển qua ứng dụng. Ví dụ: NavigationUI sử dụng nhãn đích từ biểu đồ điều hướng để luôn cập nhật tiêu đề của thanh ứng dụng trên cùng.

<navigation>
    <fragment ...
              android:label="Page title">
      ...
    </fragment>
</navigation>

Khi sử dụng NavigationUI cùng với cách triển khai thanh ứng dụng trên cùng theo thảo luận dưới đây, nhãn bạn đính kèm với đích có thể được tự động điền qua các đối số được cung cấp tới đích bằng cách sử dụng định dạng của {argName} trong nhãn.

NavigationUI hỗ trợ các loại thanh ứng dụng trên cùng sau đây:

Để biết thêm thông tin về thanh ứng dụng, hãy xem nội dung Thiết lập thanh ứng dụng.

Thận trọng:Toolbar làm đối số cho setSupportActionBar(), ActionBar sẽ giả định toàn quyền sở hữu Toolbar đó và bạn không được sử dụng bất kỳ API Toolbar nào sau cuộc gọi đó. Bạn có thể sử dụng ActionBar với NavController.

Nếu bạn truyền mộtlàm đối số chosẽ giả định toàn quyền sở hữuđó và bạn không được sử dụng bất kỳ APInào sau cuộc gọi đó. Bạn có thể sử dụng hỗ trợ cho ActionBar để kết nốivới

AppBarConfiguration

NavigationUI sử dụng đối tượng AppBarConfiguration để quản lý hoạt động của nút Điều hướng ở góc trên bên trái khu vực hiển thị của ứng dụng. Hành vi của nút Điều hướng thay đổi tuỳ thuộc vào việc người dùng có đang ở đích cấp cao nhất hay không.

Đích (destination) cấp cao nhất là đích gốc hoặc cấp cao nhất trong một nhóm đích liên quan đến hệ thống phân cấp. Đích cấp cao nhất không hiển thị nút Mũi tên lên trong thanh ứng dụng trên cùng vì không có đích cấp cao hơn. Theo mặc định, đích bắt đầu của ứng dụng là đích cấp cao nhất duy nhất.

Khi người dùng đến một đích cấp cao nhất, nút Điều hướng sẽ trở thành biểu tượng ngăn kéo nếu đích sử dụng DrawerLayout. Nếu đích không sử dụng DrawerLayout, nút Điều hướng sẽ bị ẩn. Khi người dùng đang ở đích khác, nút Điều hướng sẽ xuất hiện dưới dạng nút Mũi tên lên .
Để định cấu hình nút Điều hướng chỉ sử dụng đích bắt đầu làm đích cấp cao nhất, hãy tạo một đối tượng AppBarConfiguration rồi truyền vào biểu đồ điều hướng tương ứng, như minh hoạ dưới đây:

Kotlin

val appBarConfiguration = AppBarConfiguration(navController.graph)

Java

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

Trong một số trường hợp, bạn có thể phải xác định nhiều đích cấp cao nhất thay vì sử dụng đích xuất phát mặc định. Việc dùng BottomNavigationView là một trường hợp sử dụng phổ biến cho trường hợp này, trong đó bạn có thể có các màn hình đồng cấp không liên quan đến phân cấp và mỗi màn hình có thể có các đích đến liên quan riêng. Đối với các trường hợp như vậy, bạn có thể truyền một nhóm mã nhận dạng đích đến hàm khởi tạo, như dưới đây:

Kotlin

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

Java

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

Tạo Thanh công cụ

Để Tạo thanh công cụ (Toolbar) bằng NavigationUI, trước tiên, hãy xác định thanh đps trong hoạt động chính của bạn, như minh hoạ dưới đây:

<LinearLayout>
    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar" />
    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        ... />
    ...
</LinearLayout>

Tiếp theo, hãy gọi setupWithNavController() qua phương thức onCreate() của hoạt động chính như minh hoạ trong ví dụ sau:

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

Java

@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, appBarConfiguration);
}

Lưu ý:Toolbar, tính năng Điều hướng sẽ tự động xử lý các sự kiện nhấp chuột cho nút Điều hướng, vì vậy, bạn không cần ghi đè

Khi sử dụng, tính năng Điều hướng sẽ tự động xử lý các sự kiện nhấp chuột cho nút Điều hướng, vì vậy, bạn không cần ghi đè onSupportNavigateUp()

Để định cấu hình sao cho nút Điều hướng xuất hiện dưới dạng nút Lên cho mọi đích, hãy chuyển một tập hợp mã nhận dạng đích trống cho các đích cấp cao nhất của bạn khi tạo AppBarConfiguration. Điều này có thể hữu ích chẳng hạn như nếu bạn có hoạt động thứ hai và cần hiển thị nút Lên trong Toolbar trên tất cả các đích. Điều này cho phép người dùng quay lại hoạt động mẹ khi không có đích nào khác trên ngăn xếp lui Bạn có thể sử dụng setFallbackOnNavigateUpListener() để kiểm soát hành vi dự phòng cho trường hợp navigateUp() không làm gì khác, như thể hiện trong ví dụ sau:

Kotlin

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

    val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
    val navController = navHostFragment.navController
    val appBarConfiguration = AppBarConfiguration(
        topLevelDestinationIds = setOf(),
        fallbackOnNavigateUpListener = ::onSupportNavigateUp
    )
    findViewById<Toolbar>(R.id.toolbar)
        .setupWithNavController(navController, appBarConfiguration)
}

Java

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

    NavHostFragment navHostFragment = (NavHostFragment) supportFragmentManager.findFragmentById(R.id.nav_host_fragment);
    NavController navController = navHostFragment.getNavController();
    AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder()
        .setFallbackOnNavigateUpListener(::onSupportNavigateUp)
        .build();
    Toolbar toolbar = findViewById(R.id.toolbar);
    NavigationUI.setupWithNavController(
            toolbar, navController, appBarConfiguration);
}

Bao gồm CollapsingToolbarLayout

Để đưa CollapsingToolbarLayout vào Thanh công cụ, trước tiên, hãy xác định Thanh công cụ và bố cục xung quanh trong hoạt động của bạn, như thể hiện dưới đây:

<LinearLayout>
    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/tall_toolbar_height">

        <com.google.android.material.appbar.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">

            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"/>
        </com.google.android.material.appbar.CollapsingToolbarLayout>
    </com.google.android.material.appbar.AppBarLayout>

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

Tiếp theo, hãy gọi setupWithNavController() qua phương thức onCreate của hoạt động chính như thể hiện dưới đây:

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 navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
    val navController = navHostFragment.navController
    val appBarConfiguration = AppBarConfiguration(navController.graph)
    layout.setupWithNavController(toolbar, navController, appBarConfiguration)
}

Java

@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);
    NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment);
    NavController navController = navHostFragment.getNavController();
    AppBarConfiguration appBarConfiguration =
            new AppBarConfiguration.Builder(navController.getGraph()).build();
    NavigationUI.setupWithNavController(layout, toolbar, navController, appBarConfiguration);
}

Thanh thao tác

Để hỗ trợ chức năng di chuyển cho thanh thao tác (action bar) mặc định, hãy gọi setupActionBarWithNavController() qua phương thức onCreate() của hoạt động chính như thể hiện dưới đây: Xin lưu ý rằng bạn cần khai báo AppBarConfiguration bên ngoài onCreate() vì bạn cũng sử dụng chế độ này khi ghi đè onSupportNavigateUp():

Kotlin

private lateinit var appBarConfiguration: AppBarConfiguration

...

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

    val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
    val navController = navHostFragment.navController
    appBarConfiguration = AppBarConfiguration(navController.graph)
    setupActionBarWithNavController(navController, appBarConfiguration)
}

Java

AppBarConfiguration appBarConfiguration;

...

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

    NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment);
    NavController navController = navHostFragment.getNavController();
    appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();
    NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
}

Tiếp theo, hãy ghi đè onSupportNavigateUp() để xử lý xử lý di chuyển Lên:

Kotlin

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

Java

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

Hỗ trợ các biến thể của thanh ứng dụng

Việc thêm thanh ứng dụng trên cùng vào hoạt động sẽ hoạt động tốt khi bố cục của thanh ứng dụng tương tự nhau đối với mỗi đích trong ứng dụng. Tuy nhiên, nếu thanh ứng dụng trên cùng thay đổi đáng kể trên các đích, hãy cân nhắc xoá thanh ứng dụng trên cùng khỏi hoạt động rồi chuyển sang xác định thanh đó trong từng đoạn đích.

Ví dụ: một trong các đích có thể sử dụng Toolbar tiêu chuẩn, trong khi một đích khác sử dụng AppBarLayout để tạo thanh ứng dụng phức tạp hơn với các thẻ, như thể hiện trong hình 2.

hai biến thể thanh ứng dụng trên cùng; một thanh công cụ chuẩn ở bên trái và một appbarlayout với thanh công cụ và các thẻ ở bên phải
Hình 2. Hai biến thể thanh ứng dụng. Ở bên trái, Toolbar tiêu chuẩn. Ở bên phải, AppBarLayout chứa Toolbar và các thẻ.

Để triển khai ví dụ này trong các mảnh đích bằng cách sử dụng NavigationUI, trước tiên, hãy xác định thanh ứng dụng trong mỗi bố cục mảnh, bắt đầu bằng mảnh đích sử dụng thanh công cụ chuẩn:

<LinearLayout>
    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        ... />
    ...
</LinearLayout>

Tiếp theo, hãy xác định mảnh đích sử dụng thanh ứng dụng có các thẻ:

<LinearLayout>
    <com.google.android.material.appbar.AppBarLayout
        ... />

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            ... />

        <com.google.android.material.tabs.TabLayout
            ... />

    </com.google.android.material.appbar.AppBarLayout>
    ...
</LinearLayout>

Logic của cấu hình điều hướng là như nhau đối với cả hai mảnh này, ngoại trừ bạn nên gọi setupWithNavController() từ bên trong phương thức onViewCreated() của từng mảnh, thay vì khởi chạy các hoạt động từ hoạt động:

Kotlin

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    val navController = findNavController()
    val appBarConfiguration = AppBarConfiguration(navController.graph)

    view.findViewById<Toolbar>(R.id.toolbar)
            .setupWithNavController(navController, appBarConfiguration)
}

Java

@Override
public void onViewCreated(@NonNull View view,
                          @Nullable Bundle savedInstanceState) {
    NavController navController = Navigation.findNavController(view);
    AppBarConfiguration appBarConfiguration =
            new AppBarConfiguration.Builder(navController.getGraph()).build();
    Toolbar toolbar = view.findViewById(R.id.toolbar);

    NavigationUI.setupWithNavController(
            toolbar, navController, appBarConfiguration);
}

Lưu ý:

Việc đặt thanh ứng dụng trên cùng vào bố cục mảnh đích sẽ dẫn đến việc thanh ứng dụng hoạt động với phần còn lại của bố cục trong quá trình chuyển đổi mảnh đã đặt chế độ chuyển đổi.

Gắn đích với mục trong trình đơn

NavigationUI cũng cung cấp các trình trợ giúp để liên kết các đích với thành phần giao diện người dùng theo trình đơn. NavigationUI chứa một phương thức trợ giúp, onNavDestinationSelected(), sử dụng MenuItem cùng với NavController lưu trữ đích được liên kết. Nếu id của MenuItem khớp với id của đích, thì NavController có thể điều hướng đến đích đó.

Ví dụ: các đoạn mã XML dưới đây xác định một mục trong trình đơn và một đích đến có id phổ biến là 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>

Nếu bạn thêm trình đơn qua onCreateOptionsMenu() của Hoạt động, chẳng hạn như khi bạn có thể liên kết các mục trong trình đơn với các đích bằng cách ghi đè phần Hoạt động onOptionsItemSelected() để gọi onNavDestinationSelected() như trong ví dụ sau:

Kotlin

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

Java

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

Bây giờ, khi người dùng nhấp vào mục trong trình đơn details_page_fragment, ứng dụng
sẽ tự động chuyển đến đích tương ứng bằng cùng một id.

Thêm ngăn điều hướng

Ngăn điều hướng (navigation drawer) là một bảng điều khiển trên giao diện người dùng cho thấy trình đơn điều hướng chính của ứng dụng.
Ngăn này sẽ xuất hiện khi người dùng nhấn vào biểu tượng ngăn trong thanh ứng dụng hoặc khi người dùng vuốt từ mép trái màn hình.

một ngăn mở cho thấy trình đơn điều hướng
Hình 3. Một ngăn mở cho thấy trình đơn điều hướng.

Biểu tượng ngăn kéo xuất hiện trên tất cả đích cấp cao nhất sử dụng DrawerLayout.

Để thêm một ngăn điều hướng, trước tiên, hãy khai báo DrawerLayout làm thành phần hiển thị gốc. Bên trong DrawerLayout, hãy thêm một bố cục cho nội dung chính trên giao diện người dùng và một thành phần hiển thị khác chứa nội dung của ngăn điều hướng.

Ví dụ: bố cục sau sử dụng DrawerLayout với hai thành phần hiển thị con: một
NavHostFragment để chứa nội dung chính và một NavigationView cho nội dung của ngăn điều hướng.

<?xml version="1.0" encoding="utf-8"?>
<!-- Use DrawerLayout as root container for activity -->
<androidx.drawerlayout.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) -->
    <androidx.fragment.app.FragmentContainerView
        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 -->
    <com.google.android.material.navigation.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true" />

</androidx.drawerlayout.widget.DrawerLayout>

Tiếp theo, hãy kết nối DrawerLayout với biểu đồ điều hướng bằng cách chuyển biểu đồ đó đến AppBarConfiguration, như trong ví dụ sau:

Kotlin

val appBarConfiguration = AppBarConfiguration(navController.graph, drawerLayout)

Java

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

Lưu ý:NavigationUI,

Khi sử dụng thanh ứng dụng trên cùng sẽ tự động chuyển đổi giữa biểu tượng ngăn kéo và biểu tượng Lên khi đích hiện tại thay đổi. Bạn không cần phải sử dụng ActionBarDrawerToggle

Tiếp theo, trong lớp hoạt động chính, hãy gọi setupWithNavController() qua phương thức onCreate() của hoạt động chính như thể hiện dưới đây:

Kotlin

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

    ...

    val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
    val navController = navHostFragment.navController
    findViewById<NavigationView>(R.id.nav_view)
        .setupWithNavController(navController)
}

Java

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

    ...

    NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment);
    NavController navController = navHostFragment.getNavController();
    NavigationView navView = findViewById(R.id.nav_view);
    NavigationUI.setupWithNavController(navView, navController);
}

Lưu ý:

Khi thiết lập ngăn điều hướng, bạn cũng phải thiết lập biểu đồ điều hướng và xml trình đơn như mô tả trong nội dung Gắn đích với mục trong trình đơn

Kể từ Navigation 2.4.0-alpha01, trạng thái của từng mục trong trình đơn sẽ được lưu và khôi phục khi bạn sử dụng setupWithNavController.

Thanh điều hướng dưới cùng

NavigationUI cũng có thể xử lý thao tác ở dưới cùng. Khi người dùng chọn một mục trong trình đơn, NavController sẽ gọi onNavDestinationSelected() và tự động cập nhật mục đã chọn trong thanh điều hướng dưới cùng (bottom navigation bar).

thanh điều hướng ở dưới cùng
Hình 4. Một thanh điều hướng ở dưới cùng.

Để tạo thanh điều hướng dưới cùng trong ứng dụng, trước tiên, hãy xác định thanh đó trong hoạt động chính của bạn, như thể hiện dưới đây.

<LinearLayout>
    ...
    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        ... />
    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_nav"
        app:menu="@menu/menu_bottom_nav" />
</LinearLayout>

Tiếp theo, trong lớp hoạt động chính, hãy gọi setupWithNavController() qua phương thức onCreate() của hoạt động chính như thể hiện dưới đây:

Kotlin

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

    ...

    val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
    val navController = navHostFragment.navController
    findViewById<BottomNavigationView>(R.id.bottom_nav)
        .setupWithNavController(navController)
}

Java

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

    ...

    NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment);
    NavController navController = navHostFragment.getNavController();
    BottomNavigationView bottomNav = findViewById(R.id.bottom_nav);
    NavigationUI.setupWithNavController(bottomNav, navController);
}

Lưu ý:

Khi thiết lập thanh điều hướng dưới cùng, bạn cũng phải thiết lập biểu đồ điều hướng và xml trình đơn như mô tả trong nội dung Gắn đích với mục trong trình đơn

Kể từ Navigation 2.4.0-alpha01, trạng thái của từng mục trong trình đơn sẽ được lưu và khôi phục khi bạn sử dụng setupWithNavController.

Để biết ví dụ toàn diện về cách cung cấp thanh điều hướng ở dưới cùng, hãy xem, nội dung Mẫu điều hướng nâng cao cho bộ thành phần cấu trúc Android trên GitHub.

Nghe sự kiện điều hướng

Tương tác với NavController là phương thức chính để di chuyển giữa các đích. NavController có trách nhiệm thay thế nội dung của NavHost bằng đích đến mới. Trong nhiều trường hợp, các thành phần giao diện người dùng (chẳng hạn như thanh ứng dụng trên cùng hoặc các nút điều khiển cố định khác như BottomNavigationBar) nằm bên ngoài NavHost và cần được cập nhật khi bạn di chuyển giữa các đích.

NavController cung cấp giao diện OnDestinationChangedListener được gọi khi đích hiện tại của NavController hoặc đối số của thành phần này thay đổi. Bạn có thể đăng ký trình nghe mới thông qua phương thức addOnDestinationChangedListener(). Lưu ý rằng khi gọi addOnDestinationChangedListener(), nếu đích hiện tại đang tồn tại, đích đó sẽ được gửi ngay đến trình nghe

NavigationUI sử dụng OnDestinationChangedListener để làm cho các thành phần giao diện người dùng phổ biến này nhận biết được thành phần điều hướng. Tuy nhiên, hãy lưu ý rằng bạn cũng có thể sử dụng riêng OnDestinationChangedListener để giúp thành phần giao diện người dùng tuỳ chỉnh hoặc logic doanh nghiệp nhận biết được sự kiện điều hướng.

Ví dụ: có thể bạn có các thành phần giao diện người dùng phổ biến mà bạn dự định hiển thị trong một số khu vực của ứng dụng trong khi ẩn các thành phần đó trong các khu vực khác. Khi sử dụng OnDestinationChangedListener của riêng mình, bạn có thể hiện hoặc ẩn các thành phần giao diện người dùng này một cách có chọn lọc dựa trên đích, như trong ví dụ sau:

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
   }
}

Java

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

Trình nghe dựa trên đối số

Thay vào đó, bạn cũng có thể sử dụng các đối số có giá trị mặc định trong biểu đồ điều hướng. Trình điều khiển giao diện người dùng thích hợp có thể sử dụng biểu đồ này để cập nhật trạng thái. Ví dụ: thay vì dựa vào logic trong OnDestinationChangedListener trên mã nhận dạng đích như trong ví dụ trước, chúng ta có thể tạo một đối số trong NavGraph:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/navigation\_graph"
    app:startDestination="@id/fragmentOne">
    <fragment
        android:id="@+id/fragmentOne"
        android:name="com.example.android.navigation.FragmentOne"
        android:label="FragmentOne">
        <action
            android:id="@+id/action\_fragmentOne\_to\_fragmentTwo"
            app:destination="@id/fragmentTwo" />
    </fragment>
    <fragment
        android:id="@+id/fragmentTwo"
        android:name="com.example.android.navigation.FragmentTwo"
        android:label="FragmentTwo">
        <argument
            android:name="ShowAppBar"
            android:defaultValue="true" />
    </fragment>
</navigation>

Đối số này không được sử dụng khi di chuyển đến đích mà thay vào đó là để đính kèm thông tin bổ sung vào đích bằng cách sử dụng defaultValue. Trong trường hợp này, giá trị cho biết liệu thanh ứng dụng có nên hiện ra khi ở trên đích này hay không.

Bây giờ, chúng ta có thể thêm OnDestinationChangedListener trong Activity:

Kotlin

navController.addOnDestinationChangedListener { _, _, arguments ->
    appBar.isVisible = arguments?.getBoolean("ShowAppBar", false) == true
}

Java

navController.addOnDestinationChangedListener(
        new NavController.OnDestinationChangedListener() {
            @Override
            public void onDestinationChanged(
                    @NonNull NavController controller,
                    @NonNull NavDestination destination,
                    @Nullable Bundle arguments
            ) {
                boolean showAppBar = false;
                if (arguments != null) {
                    showAppBar = arguments.getBoolean("ShowAppBar", false);
                }
                if(showAppBar) {
                    appBar.setVisibility(View.VISIBLE);
                } else {
                    appBar.setVisibility(View.GONE);
                }
            }
        }
);

NavController gọi lệnh gọi lại này bất cứ khi nào đích điều hướng thay đổi. Activity nay có thể cập nhật trạng thái hoặc chế độ hiển thị của các thành phần giao diện người dùng mà ứng dụng sở hữu dựa trên các đối số nhận được trong lệnh gọi lại.

Một ưu điểm của phương pháp này là Activity chỉ xem được các đối số trong biểu đồ điều hướng mà không biết từng vai trò và trách nhiệm Fragment riêng lẻ. Tương tự, từng phần riêng lẻ không biết về Activity chứa và các thành phần giao diện người dùng mà phần đó sở hữu.

Tài nguyên khác

Để tìm hiểu thêm về hoạt động điều hướng, hãy xem một số tài nguyên bổ sung sau đây.

Mẫu

Lớp học lập trình

Bài đăng trên blog

Video