デスティネーションを作成する

既存のフラグメントまたはアクティビティからデスティネーションを作成できます。また、Navigation Editor を使用して、新しいデスティネーションを作成する、または後でフラグメントあるいはアクティビティに置き換えるプレースホルダを作成することもできます。

既存のフラグメントまたはアクティビティからデスティネーションを作成する

既存のデスティネーション タイプをナビゲーション グラフに追加する場合は、Navigation Editor 内で、[New Destination]()をクリックして、表示されるプルダウンから、目的のデスティネーションをクリックします。ナビゲーション グラフの [Design] ビューにデスティネーションのプレビューが表示され、[Text] ビューに対応する XML が表示されます。

新しいフラグメント デスティネーションを作成する

Navigation Editor を使用して新しいデスティネーション タイプを追加する手順は次のとおりです。

  1. Navigation Editor 内で、[New Destination] アイコン をクリックして、[Create new destination] をクリックします。
  2. 表示された [New Android Component] ダイアログで、フラグメントを作成します。フラグメントの詳細については、フラグメントのドキュメントをご覧ください。

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 デスティネーションの作成は、Fragment デスティネーションの作成に似ています。ただし、Activity デスティネーションの性質は大きく異なります。

デフォルトでは、Navigation ライブラリは NavControllerActivity レイアウトにアタッチし、アクティブなナビゲーション グラフのスコープはアクティブな 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-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>

対応する Activity デスティネーションは、マニフェスト エントリ内のものと一致する action 属性と data 属性で構成する必要があります。

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

targetPackage を現在の applicationId に指定すると、メインアプリを含む現在のアプリへのスコープ設定が制限されます。

特定のアプリをデスティネーションにするケースでは、同じメカニズムを使用できます。次の例では、デスティネーションが、com.example.android.another.app という applicationId のアプリとなるように定義しています。

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

動的な引数

前の例では、固定 URL を使用してデスティネーションに移動していました。追加情報が URL の一部として送信される、動的 URL をサポートする必要がある場合もあります。たとえば、https://example.com?userId=<actual user ID> のような形式の URL のユーザー ID を送信するとします。

この場合、data 属性の代わりに dataPattern を使用します。そうすると、引数を指定して 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 Args または Bundle を使用して 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);

この例では、{userId}someUser に置き換えて、https://example.com?userId=someUser の URI 値を作成しています。

プレースホルダ デスティネーション

プレースホルダを使用して、未実装のデスティネーションを示すことができます。 プレースホルダは、デスティネーションの視覚的な表現として機能します。Navigation Editor 内では、通常のデスティネーションと同様に、プレースホルダを使用できます。