创建目的地

您可以从现有的 Fragment 或 Activity 创建目的地。您还可以使用 Navigation Editor 创建新目的地,或创建占位符以便稍后替换为 Fragment 或 Activity。

从现有的 Fragment 或 Activity 创建目的地

在 Navigation Editor 中,如果您有现有的目的地类型要添加到导航图,请点击 New Destination ,然后在显示的下拉列表中,点击相应目的地。您现在可以在导航图的 Design 视图中看到目的地的预览,并在 Text 视图中看到相应 XML 文本。

创建新的 Fragment 目的地

如需使用 Navigation Editor 添加新目的地类型,请执行以下操作:

  1. 在 Navigation Editor 中,点击 New Destination 图标 ,然后点击 Create new destination
  2. 在随即显示的 New Android Component 对话框中,创建您的 Fragment。如需详细了解 Fragment,请参阅 Fragment 文档

当您返回到 Navigation Editor 中时,会发现 Android Studio 已将此目的地添加到图中。

图 1 显示了目的地和占位符目的地的示例。

图 1. 目的地和占位符

从 DialogFragment 创建目的地

如果您已有 DialogFragment,可以使用 <dialog> 元素将该对话框添加到您的导航图,如以下示例所示:

<?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/nav_graph">

...

<dialog
    android:id="@+id/my_dialog_fragment"
    android:name="androidx.navigation.myapp.MyDialogFragment">
    <argument android:name="myarg" android:defaultValue="@null" />
        <action
            android:id="@+id/myaction"
            app:destination="@+id/another_destination"/>
</dialog>

...

</navigation>

创建新的 activity 目的地

创建 Activity 目的地的过程与创建 Fragment 目的地类似。但是,Activity 目的地的性质完全不同。

默认情况下,Navigation 库会将 NavController 附加到 Activity 布局,并且处于活跃状态的导航图的作用域限定为处于活跃状态的 Activity。如果用户导航到其他 Activity,则当前的导航图不再位于作用域内。这意味着,Activity 目的地应被视为导航图中的一个端点。

如要添加 Activity 目的地,请使用其完全限定的类名称指定目的地 Activity

<?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/simpleFragment">

    <activity
        android:id="@+id/sampleActivityDestination"
        android:name="com.example.android.navigation.activity.DestinationActivity"
        android:label="@string/sampleActivityTitle" />
</navigation>

此 XML 相当于以下对 startActivity() 的调用:

Kotlin

startActivity(Intent(context, DestinationActivity::class.java))

Java

startActivity(new Intent(context, DestinationActivity.class));

在某些情况下,您可能会发现此方法不适合。例如,您可能在 activity 类中未采用编译时依赖项,或者您可能会更倾向于使用运行某个隐式 intent 的间接层。目的地 Activity 的清单条目中的 intent-filter 决定了您需要如何构造 Activity 目的地。

例如,请考虑使用以下清单文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.navigation.activity">
    <application>
        <activity android:name=".DestinationActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <data
                    android:host="example.com"
                    android:scheme="https" />
                <category android:name="android.intent.category.BROWSABLE" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>
</manifest>

您需要使用与清单条目中匹配的 actiondata 属性来配置相应的 Activity 目的地:

<?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/simpleFragment">
    <activity
        android:id="@+id/localDestinationActivity"
        android:label="@string/localActivityTitle"
        app:action="android.intent.action.VIEW"
        app:data="https://example.com"
        app:targetPackage="${applicationId}" />
</navigation>

为当前 applicationId 指定 targetPackage可将作用域限定为当前应用(其包含主应用)。

如果您希望将特定应用作为目的地,可以使用上述机制。以下示例将目的地定义为 applicationIdcom.example.android.another.app 的应用。

<?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/simpleFragment">
    <activity
        android:id="@+id/localDestinationActivity"
        android:label="@string/localActivityTitle"
        app:action="android.intent.action.VIEW"
        app:data="https://example.com"
        app:targetPackage="com.example.android.another.app" />
</navigation>

动态参数

前面的示例使用固定网址来导航到目的地。您可能还需要支持动态网址,在动态网址中,会将其他信息作为网址的一部分发送。例如,您可以在格式类似于 https://example.com?userId=<actual user ID> 的网址中发送用户 ID。

在这种情况下,请使用 dataPattern,而不是 data 属性。然后,您可以为 dataPattern 值中的具名占位符提供要被替代的参数:

<?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/simpleFragment">
    <activity
        android:id="@+id/localDestinationActivity"
        android:label="@string/localActivityTitle"
        app:action="android.intent.action.VIEW"
        app:dataPattern="https://example.com?userId={userId}"
        app:targetPackage="com.example.android.another.app">
        <argument
            android:name="userId"
            app:argType="string" />
    </activity>
</navigation>

在此示例中,您可以使用 Safe ArgsBundle 指定 userId 值:

Kotlin

navController.navigate(
    R.id.localDestinationActivity,
    bundleOf("userId" to "someUser")
)

Java

Bundle args = new Bundle();
args.putString("userId", "someUser");
navController.navigate(R.id.localDestinationActivity, args);

此示例用 someUser 替换了 {userId},创建了一个 URI 值 https://example.com?userId=someUser

占位符目的地

您可以使用占位符来表示尚未实现的目的地。 占位符充当目的地的视觉表示形式。在 Navigation Editor 中,您可以像使用任何其他目的地一样使用占位符。