بهترین شیوه های ناوبری برای پروژه های چند ماژول

یک نمودار ناوبری می تواند از هر ترکیبی از موارد زیر تشکیل شود:

  • یک مقصد منحصر به فرد، مانند یک مقصد <fragment> .
  • یک نمودار تو در تو که مجموعه ای از مقاصد مرتبط را در بر می گیرد.
  • یک عنصر <include> ، که به شما امکان می دهد یک فایل گراف ناوبری دیگر را طوری جاسازی کنید که انگار تو در تو است.

این انعطاف‌پذیری به شما امکان می‌دهد نمودارهای پیمایش کوچک‌تر را با هم ترکیب کنید تا نمودار ناوبری کامل برنامه خود را تشکیل دهید، حتی اگر آن نمودارهای ناوبری کوچک‌تر توسط ماژول‌های جداگانه ارائه شده باشد.

برای مثال‌های موجود در این مبحث، هر ماژول ویژگی حول یک ویژگی متمرکز شده است و یک نمودار ناوبری واحد ارائه می‌کند که تمام مقاصد مورد نیاز برای اجرای آن ویژگی را در بر می‌گیرد. در یک برنامه تولیدی، ممکن است ماژول‌های فرعی زیادی در سطح پایین‌تری داشته باشید که جزئیات پیاده‌سازی این ماژول ویژگی سطح بالاتر هستند. هر یک از این ماژول های ویژگی، به طور مستقیم یا غیرمستقیم، در ماژول app شما گنجانده شده است. نمونه برنامه چند ماژول استفاده شده در این سند دارای ساختار زیر است:

نمودار وابستگی برای یک نمونه برنامه چند ماژوله
مقصد شروع برنامه نمونه
شکل 1. معماری برنامه و مقصد شروع برای برنامه مثال.

هر ماژول ویژگی یک واحد مستقل با نمودار ناوبری و مقاصد خاص خود است. ماژول app به هر کدام بستگی دارد و آنها را به عنوان جزئیات پیاده سازی در فایل build.gradle خود اضافه می کند، همانطور که نشان داده شده است:

شیار

dependencies {
    ...
    implementation project(":feature:home")
    implementation project(":feature:favorites")
    implementation project(":feature:settings")

کاتلین

dependencies {
    ...
    implementation(project(":feature:home"))
    implementation(project(":feature:favorites"))
    implementation(project(":feature:settings"))

نقش ماژول app

ماژول app مسئول ارائه نمودار کامل برای برنامه شما و افزودن NavHost به UI شما است. در نمودار پیمایش ماژول app ، می‌توانید با استفاده از <include> به نمودارهای کتابخانه ارجاع دهید. در حالی که استفاده از <include> از نظر عملکردی مانند استفاده از یک گراف تودرتو است، <include> از نمودارهای دیگر ماژول های پروژه یا پروژه های کتابخانه پشتیبانی می کند، همانطور که در مثال زیر نشان داده شده است:

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/home_nav_graph">

    <include app:graph="@navigation/home_navigation" />
    <include app:graph="@navigation/favorites_navigation" />
    <include app:graph="@navigation/settings_navigation" />
</navigation>

هنگامی که یک کتابخانه در نمودار ناوبری سطح بالا گنجانده شد، می توانید در صورت نیاز به نمودارهای کتابخانه بروید . به عنوان مثال، می‌توانید یک عمل برای پیمایش به نمودار تنظیمات از یک قطعه در نمودار ناوبری خود ایجاد کنید، همانطور که نشان داده شده است:

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/home_nav_graph">

    <include app:graph="@navigation/home_navigation" />
    <include app:graph="@navigation/favorites_navigation" />
    <include app:graph="@navigation/settings_navigation" />

    <fragment
        android:id="@+id/random_fragment"
        android:name="com.example.android.RandomFragment"
        android:label="@string/fragment_random" >
        <!-- Launch into Settings Navigation Graph -->
        <action
            android:id="@+id/action_random_fragment_to_settings_nav_graph"
            app:destination="@id/settings_nav_graph" />
    </fragment>
</navigation>

هنگامی که چندین ماژول ویژگی نیاز به ارجاع به مجموعه مشترکی از مقصدها، مانند نمودار ورود دارند، نباید آن مقاصد مشترک را در نمودار ناوبری هر ماژول ویژگی قرار دهید. در عوض، آن مقاصد رایج را به نمودار ناوبری ماژول app خود اضافه کنید. سپس هر ماژول ویژگی می‌تواند در میان ماژول‌های ویژگی حرکت کند تا به آن مقاصد رایج حرکت کند.

در مثال قبلی، اکشن مقصد ناوبری @id/settings_nav_graph را مشخص می‌کند. این شناسه به مقصدی اشاره دارد که در نمودار موجود در @navigation/settings_navigation.

ناوبری سطح بالا در ماژول برنامه

مولفه Navigation شامل یک کلاس NavigationUI است. این کلاس شامل متدهای ثابتی است که پیمایش را با نوار برنامه بالا، کشوی ناوبری و پیمایش پایین مدیریت می کند. اگر مقاصد سطح بالای برنامه شما از عناصر رابط کاربری ارائه شده توسط ماژول های ویژگی تشکیل شده است، ماژول app مکانی طبیعی برای قرار دادن عناصر ناوبری و رابط کاربری سطح بالا است. از آنجایی که ماژول برنامه به ماژول های ویژگی مشترک بستگی دارد، همه مقصدهای آنها از طریق کد تعریف شده در ماژول برنامه شما قابل دسترسی است. این بدان معناست که اگر شناسه مورد با شناسه مقصد مطابقت داشته باشد، می‌توانید از NavigationUI برای گره زدن مقصدها به آیتم‌های منو استفاده کنید.

در شکل 2، ماژول app مثال، BottomNavigationView در فعالیت اصلی خود تعریف می کند. شناسه‌های آیتم‌های منو در منو با شناسه‌های نمودار پیمایش نمودارهای کتابخانه مطابقت دارند:

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

    <item
        android:id="@id/home_nav_graph"
        android:icon="@drawable/ic_home"
        android:title="Home"
        app:showAsAction="ifRoom"/>

    <item
        android:id="@id/favorites_nav_graph"
        android:icon="@drawable/ic_favorite"
        android:title="Favorites"
        app:showAsAction="ifRoom"/>

    <item
        android:id="@id/settings_nav_graph"
        android:icon="@drawable/ic_settings"
        android:title="Settings"
        app:showAsAction="ifRoom" />
</menu>

برای اینکه به NavigationUI اجازه دهید ناوبری پایین را مدیریت کند، همانطور که در مثال زیر نشان داده شده است، از onCreate() setupWithNavController() در کلاس فعالیت اصلی خود فراخوانی کنید:

کاتلین

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    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)
}

جاوا

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    NavHostFragment navHostFragment =
            (NavHostFragment) supportFragmentManager.findFragmentById(R.id.nav_host_fragment);
    NavController navController = navHostFragment.getNavController();
    BottomNavigationView bottomNav = findViewById(R.id.bottom_nav);

    NavigationUI.setupWithNavController(bottomNav, navController);
}

با قرار دادن این کد، وقتی کاربر روی آیتم ناوبری پایین کلیک می‌کند، NavigationUI به نمودار کتابخانه مناسب هدایت می‌شود.

به خاطر داشته باشید که معمولاً تمرین بدی است که ماژول برنامه شما وابستگی سختی به یک مقصد خاص داشته باشد که عمیقاً در نمودار ناوبری ماژول های ویژگی شما تعبیه شده است. در بیشتر موارد، شما می خواهید ماژول برنامه شما فقط در مورد نقطه ورود به هر نمودار ناوبری تعبیه شده یا گنجانده شده بداند (این امر در خارج از ماژول های ویژگی نیز صدق می کند). اگر نیاز دارید به مقصدی در عمق نمودار پیمایش کتابخانه خود پیوند دهید، روش ترجیحی برای انجام این کار استفاده از پیوند عمیق است. پیوند عمیق همچنین تنها راه برای یک کتابخانه برای پیمایش به مقصد در نمودار ناوبری کتابخانه دیگر است.

پیمایش در میان ماژول های ویژگی

در زمان کامپایل، ماژول های ویژگی مستقل نمی توانند یکدیگر را ببینند، بنابراین نمی توانید از شناسه ها برای حرکت به مقصد در ماژول های دیگر استفاده کنید. در عوض، از یک پیوند عمیق برای پیمایش مستقیم به مقصدی که با پیوند عمیق ضمنی مرتبط است، استفاده کنید.

در ادامه مثال قبلی، تصور کنید که باید از یک دکمه در ماژول :feature:home به مقصدی که در ماژول :feature:settings تودرتو است، حرکت کنید. می توانید این کار را با افزودن یک پیوند عمیق به مقصد در نمودار ناوبری تنظیمات انجام دهید، همانطور که نشان داده شده است:

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/settings_nav_graph"
    app:startDestination="@id/settings_fragment_one">

    ...

    <fragment
        android:id="@+id/settings_fragment_two"
        android:name="com.example.google.login.SettingsFragmentTwo"
        android:label="@string/settings_fragment_two" >

        <deepLink
            app:uri="android-app://example.google.app/settings_fragment_two" />
    </fragment>
</navigation>

سپس کد زیر را به onClickListener دکمه در قطعه اصلی اضافه کنید:

کاتلین

button.setOnClickListener {
    val request = NavDeepLinkRequest.Builder
        .fromUri("android-app://example.google.app/settings_fragment_two".toUri())
        .build()
    findNavController().navigate(request)
}

جاوا

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        NavDeepLinkRequest request = NavDeepLinkRequest.Builder
            .fromUri(Uri.parse("android-app://example.google.app/settings_fragment_two"))
            .build();
        NavHostFragment.findNavController(this).navigate(request);
    }
});

برخلاف پیمایش با استفاده از شناسه‌های اقدام یا مقصد، می‌توانید به هر URI در هر نمودار، حتی در بین ماژول‌ها، پیمایش کنید.

هنگام پیمایش با استفاده از URI، پشته پشتی تنظیم مجدد نمی شود. این رفتار برخلاف پیمایش پیوند عمیق صریح است، که در آن پشته پشتی هنگام پیمایش جایگزین می‌شود.