导航架构组件简化了应用中目标之间导航的实现。 一组目的地组成应用程序的导航图。
目的地是您可以在应用中导航到的任何位置。 虽然目标通常是代表特定屏幕的片段,但导航架构组件支持其他目标类型:
- 活动。
- 导航图和子图 - 当目标是图形或子图时,导航到该图或子图的起始目标。
- 自定义目标类型。
导航架构组件基于导航原理实现。
注意:如果要在Android Studio中使用导航架构组件,则必须使用Android Studio 3.2 Canary 14或更高版本。
一、在项目中设置导航
在创建导航图之前,必须为项目设置导航架构组件。 要在Android Studio中设置项目,请执行以下步骤。
- 如果使用Beta,Release Candidate或Stable构建,则必须启用导航编辑器。 单击文件>设置(Mac上的Android Studio>首选项),在左窗格中选择实验类别,选中启用导航编辑器,然后重新启动Android Studio。
- 将以下导航架构组件添加到您的应用程序或模块的build.gradle文件中。
- 在“项目”窗口中,右键单击res目录,然后选择“新建”>“Android资源文件”。 出现“新建资源文件”对话框。
- 在“文件名”字段中键入名称,例如“nav_graph”。
- 从“资源类型”下拉列表中选择“导航”。
- 单击确定。 发生以下情况:
a. 在res目录中创建导航资源目录。
b. 在导航目录中创建nav_graph.xml
文件。
c.nav_graph.xml
文件在导航编辑器中打开。 此xml文件包含导航图。 - 单击“文本”选项卡以切换到XML文本视图。 空导航图的XML如下所示:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android">
</navigation>
- 单击“设计”返回“导航编辑器”。
二、浏览导航编辑器
在导航编辑器中,您可以快速构建导航图,而不是手动构建图形的XML。 如图2所示,导航编辑器有三个部分:
导航编辑器的部分是:
- “目标”列表 - 列出“曲线图编辑器”中当前的所有目标。
- 图表编辑器 - 包含导航图的可视化表示。
- 属性编辑器 - 包含与导航图中的目标和操作关联的属性。
三、确定目的地
创建导航图的第一步是确定应用的目的地。 您可以从现有项目中的片段和活动创建空白目标或创建目标。
注意:导航体系结构组件专为具有一个具有多个片段目标的主要活动的应用程序而设计。 主要活动“托管”导航图。 在具有多个活动目标的应用中,每个附加活动都会托管自己的导航图。 修改主机导航活动将在本文档的后面部分讨论。
要确定应用的目标,请使用以下步骤。
在“曲线图编辑器”中,单击“New Destination” 出现“New Destination”对话框。
单击“Create blank destination”或单击片段或活动。 将出现“新建Android组件”对话框。
在“片段名称”字段中输入名称。 此名称是片段类的名称。
在“片段布局名称”字段中输入名称。 此名称是片段的布局文件的名称。
单击完成。 表示目标的框显示在“曲线图编辑器”和“目标”列表中。 发生以下情况:
- 如果您创建了空白目标,则“图表编辑器”会在目标中显示消息“Hello blank fragment”。 如果单击片段或活动,则“图表编辑器”将显示该活动或片段的布局预览。
- 为您的项目创建Fragment子类。 此类具有您在步骤3中指定的名称。
- 为您的项目创建资源文件。 此文件具有您在步骤4中指定的名称。
图3显示了一个空白和一个现有目的地。
- 单击新插入的目标以突出显示目标。 “属性”面板中显示以下属性:
- 类型”字段包含“片段”或“活动”,以指示目标是否在源代码中实现为片段或活动。
- Label字段包含目标的XML布局文件的名称。
- ID字段包含将用于在代码中引用目标的目标ID。
- Class字段包含目标类的名称。
- 单击“文本”选项卡以切换到XML视图。 XML现在包含基于现有类和布局文件的名称的id,名称(类名),标签和布局属性:
<?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"
app:startDestination="@id/blankFragment">
<fragment
android:id="@+id/blankFragment"
android:name="com.example.cashdog.cashdog.BlankFragment"
android:label="Blank"
tools:layout="@layout/fragment_blank" />
</navigation>
注意:XML有一个startDestination属性,指向新空目标的id(app:startDestination =“@ + id / fragment”)。 有关起始目的地的更多信息,请参阅指定屏幕作为起始目的地。
四、连接目的地
您必须有多个目标才能连接目标。 以下是包含两个空白目标的导航图的XML:
<?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"
app:startDestination="@id/blankFragment">
<fragment
android:id="@+id/blankFragment"
android:name="com.example.cashdog.cashdog.BlankFragment"
android:label="fragment_blank"
tools:layout="@layout/fragment_blank" />
<fragment
android:id="@+id/blankFragment2"
android:name="com.example.cashdog.cashdog.BlankFragment2"
android:label="Blank2"
tools:layout="@layout/fragment_blank_fragment2" />
</navigation>
目的地使用动作连接。 连接两个目的地:
-
在图表编辑器中,将鼠标悬停在您希望用户导航的目标的右侧。 目的地上会出现一个圆圈。
-
单击并按住,将光标拖动到希望用户导航到的目标上,然后释放。 绘制一条线以指示两个目的地之间的导航。
单击箭头以突出显示该操作。 “属性”面板中显示以下属性:
- “类型”字段包含“操作”。
- ID字段包含系统为操作分配的ID。
- Destination字段包含目标片段或活动的ID。
- 单击“文本”选项卡以切换到XML视图。 已将一个操作元素添加到父目标。 该操作具有系统分配的ID和目标属性,其中包含下一个目标的ID。 例如:
<?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"
app:startDestination="@id/blankFragment">
<fragment
android:id="@+id/blankFragment"
android:name="com.example.cashdog.cashdog.BlankFragment"
android:label="fragment_blank"
tools:layout="@layout/fragment_blank" >
<action
android:id="@+id/action_blankFragment_to_blankFragment2"
app:destination="@id/blankFragment2" />
</fragment>
<fragment
android:id="@+id/blankFragment2"
android:name="com.example.cashdog.cashdog.BlankFragment2"
android:label="fragment_blank_fragment2"
tools:layout="@layout/fragment_blank_fragment2" />
</navigation>
五、将屏幕指定为起始目的地
图表编辑器在应用程序的第一个目标名称旁边放置一个房屋图标。 此图标表示这是导航图中的起始目标。 您可以使用以下步骤将另一个目标指定为起始目标:
- 从图表编辑器中,单击目标。 目的地突出显示。
- 单击“属性”面板中的“设置起始目标”。 目的地现在是起始目的地。
六、修改活动以主持导航
活动通过实施添加到活动布局的NavHost界面来托管应用程序的导航。 NavHost是一个空视图,当用户浏览您的应用程序时,目的地会被换入和换出。
Navigation Architecture Component的默认NavHost实现是NavHostFragment。
包含NavHost后,必须使用navGraph属性将导航图与NavHostFragment相关联。 以下代码段显示了如何在活动的布局文件中包含NavHostFragment并将导航图与NavHostFragment相关联:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/nav_graph"
app:defaultNavHost="true"
/>
</android.support.constraint.ConstraintLayout>
上一个示例包含一个app:defaultNavHost =“true”属性。 此属性可确保您的NavHostFragment拦截系统“后退”按钮。 您还将覆盖AppCompatActivity.onSupportNavigateUp()并调用NavController.navigateUp,如下所示:
@Override
public boolean onSupportNavigateUp() {
return Navigation.findNavController(this, R.id.nav_host_fragment).navigateUp();
}
以编程方式创建NavHostFragment
您还可以使用NavHostFragment.create()以编程方式创建具有特定图形资源的NavHostFragment,如下例所示:
NavHostFragment finalHost = NavHostFragment.create(R.navigation.example_graph);
getSupportFragmentManager().beginTransaction()
.replace(R.id.nav_host, finalHost)
.setPrimaryNavigationFragment(finalHost) // this is the equivalent to app:defaultNavHost="true"
.commit();
七、将目标绑定到UI小部件
使用NavController类导航到目标。 可以使用以下静态方法之一检索NavController:
NavHostFragment.findNavController(Fragment)
Navigation.findNavController(Activity, @IdRes int viewId)
Navigation.findNavController(View)
检索NavController后,使用其navigate()
方法导航到目标。 navigate()
方法接受资源ID。 ID可以是导航图或操作中特定目标的ID。 使用操作的ID而不是目标的资源ID具有优势,例如将过渡与导航相关联。
以下代码段显示了如何导航到ViewTransactionsFragment:
viewTransactionsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Navigation.findNavController(view).navigate(R.id.viewTransactionsAction);
}
});
Android系统维护一个包含最后访问目的地的后栈。 当用户打开应用程序时,应用程序的第一个目标位于堆栈中。 每次调用navigate()
方法都会将另一个目标放在堆栈顶部。 相反,按向上或向后按钮分别调用NavController.navigateUp()
和NavController.popBackStack()
方法,以从堆栈中弹出顶部目标。
对于按钮,您还可以使用Navigation类的createNavigateOnClickListener()
便捷方法导航到目标:
button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.next_fragment, null));
将目标绑定到菜单驱动的UI组件
您可以使用目标的id作为XML中导航抽屉或溢出菜单项的相同ID,将目标绑定到导航抽屉和溢出菜单。 以下代码段显示了详细信息屏幕目标,其ID为details_page_fragment:
<fragment android:id="@+id/details_page_fragment"
android:label="@string/details"
android:name="com.example.android.myapp.DetailsFragment" />
对目的地和菜单项使用相同的ID会自动将目的地与菜单项相关联。 以下XML显示了如何将片段目标与导航抽屉中的菜单项相关联(例如,menu_nav_drawer.xml):
<item
android:id="@id/details_page_fragment"
android:icon="@drawable/ic_details"
android:title="@string/details" />
以下XML显示了如何将详细信息目标绑定到溢出菜单(例如menu_overflow.xml):
<item
android:id="@id/details_page_fragment"
android:icon="@drawable/ic_details"
android:title="@string/details"
android:menuCategory:"secondary" />
导航架构组件包括NavigationUI类。 此类有几个静态方法,您可以使用带有导航目标的连接菜单项。 例如,以下代码显示如何使用setupWithNavController()
方法将菜单抽屉中的项目连接到NavigationView:
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
NavigationUI.setupWithNavController(navigationView, navController);
必须使用这些NavigationUI方法设置菜单驱动的导航组件,以便这些UI元素的状态与NavController的更改保持同步。
八、在目的地之间传递数据
您可以通过两种方式在目标之间传递数据:使用Bundle对象或使用安全标记Gradle插件以类型安全的方式传递数据。 使用以下步骤使用Bundle对象在目标之间传递数据。 如果您使用的是Gradle,请考虑按照类型安全的方式在目标之间传递数据中的说明。
- 在图表编辑器中,单击接收参数的目标位置。 目的地亮点。
- 单击“属性”面板的“参数”部分中的“添加”(+)。 出现空名称和默认值字段。
- 双击名称并输入参数的名称。
- 按Tab键并输入参数的默认值。
- 单击此目标之前的操作。 参数默认值应包含新添加的参数。
- 单击“文本”选项卡以切换到XML视图。 带有name和defaultValue属性的参数元素已添加到目标:
<fragment
android:id="@+id/confirmationFragment"
android:name="com.example.cashdog.cashdog.ConfirmationFragment"
android:label="fragment_confirmation"
tools:layout="@layout/fragment_confirmation">
<argument android:name="amount" android:defaultValue=”0” />
- 在您的代码中,使用navigate()方法创建一个包并将其传递到目标:
Bundle bundle = new Bundle();
bundle.putString("amount", amount);
Navigation.findNavController(view).navigate(R.id.confirmationAction, bundle);
在接收目标的代码中,使用getArguments()
方法检索包并使用其内容:
TextView tv = view.findViewById(R.id.textViewAmount);
tv.setText(getArguments().getString("amount"));
九、添加侦听器以处理导航事件
您可以使用addOnNavigatedListener()
将OnNavigatedListener添加到NavController。 OnNavigatedListener在控制器导航到新目标时接收事件。 您可以使用此处理程序进行特定于目标的更改,例如显示或隐藏某些UI元素。
调用addOnNavigatedListener()
时,如果当前目标存在,则立即将其发送给您的侦听器。
十、以类型安全的方式在目标之间传递数据
Navigation Architecture Component有一个Gradle插件,称为safeargs,它生成简单的对象和构建器类,以便对目标和操作指定的参数进行类型安全访问。 Safe args建立在Bundle方法的基础之上,但需要一些额外的代码来换取更多类型的安全性。 如果您使用的是Gradle,则可以使用safe args插件。 要添加此插件,请将“androidx.navigation.safeargs”插件添加到build.gradle文件中。 例如:
apply plugin: 'com.android.application'
apply plugin: 'androidx.navigation.safeargs'
android {
//...
}
配置Gradle插件后,请按照以下步骤使用类型安全的args。
- 在图表编辑器中,单击接收参数的目标位置。 目的地亮点。
- 单击“属性”面板的“参数”部分中的+。 出现空名称和默认值字段。
- 双击名称并输入参数的名称。
- 按Tab键并从下拉列表中选择参数的类型。
- 按Tab键并输入参数的默认值。
- 单击此目标之前的操作。 参数默认值应包含新添加的参数。
- 单击“文本”选项卡以切换到XML视图。 带有name和defaultValue属性的参数元素已添加到目标:
<fragment
android:id="@+id/confirmationFragment"
android:name="com.example.buybuddy.buybuddy.ConfirmationFragment"
android:label="fragment_confirmation"
tools:layout="@layout/fragment_confirmation">
<argument android:name="amount" android:defaultValue="1" app:type="integer"/>
</fragment>
使用safeargs插件生成代码时,会为操作以及发送和接收目标创建简单对象和构建器类。 这些课程是:
- 动作源自的目的地的类,附加“方向”一词。
因此,如果原始片段标题为SpecifyAmountFragment,则生成的类称为SpecifyAmountFragmentDirections。 这个类有一个方法,以用于传递参数的动作命名,用于捆绑参数,例如confirmationAction()
。 - 一个内部类,其名称基于用于传递参数的操作。 如果传递的操作名为confirmationAction,则该类名为ConfirmationAction。
- 传递参数的目标的类,附加单词Args。
因此,如果目标片段标题为ConfirmationFragment,则生成的类称为ConfirmationFragmentArgs。 使用此类的fromBundle()
方法来检索参数。
以下代码显示如何使用这些方法设置参数并将其传递给navigate()方法。
@Override
public void onClick(View view) {
EditText amountTv = (EditText) getView().findViewById(R.id.editTextAmount);
int amount = Integer.parseInt(amountTv.getText().toString());
ConfirmationAction action =
SpecifyAmountFragmentDirections.confirmationAction()
action.setAmount(amount)
Navigation.findNavController(view).navigate(action);
}
在接收目标的代码中,使用getArguments()方法检索包并使用其内容:
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
TextView tv = view.findViewById(R.id.textViewAmount);
int amount = ConfirmationFragmentArgs.fromBundle(getArguments()).getAmount();
tv.setText(amount + "")
}
十一、将目标分组为嵌套导航图
可以将一系列目的地分组为导航图中的子图。 子图称为嵌套图,而包含图称为“根图”。嵌套图对于组织和重用应用程序UI的各个部分非常有用,例如单独的登录流程。
与根图一样,嵌套图必须将目标标识为起始目标。 嵌套图形封装了它的目的地; 嵌套图外部的目标(例如根图上的目标)仅通过其起始目标访问嵌套图。 图6显示了简单汇款应用程序的导航图。 该图有两个流程:允许用户汇款的流程和允许用户查看其余额的流程。
要将目标分组到嵌套图中:
在“曲线图编辑器”中,按住shift并单击要包含在嵌套图形中的目标。 每个目的地都突出显示
-
打开上下文菜单,然后选择“移动到嵌套图形”>“新建图形”。 目标包含在嵌套图中。 图7显示了Graph Editor中的嵌套图。
单击嵌套图以突出显示它。 “属性”面板中显示以下属性:
- “类型”字段包含“嵌套图”。
- ID字段包含嵌套图的系统分配ID。 此ID用于引用代码中的嵌套图。
- 双击嵌套图。 将显示嵌套图中的目标。
- 在“目标”列表中,单击“根”以返回到根导航图。
- 单击“文本”选项卡以切换到XML视图。 图表中添加了嵌套导航图。 此导航图具有自己的打开和关闭导航元素。 此嵌套图的ID为sendMoneyGraph,startDestination属性指向嵌套图中的第一个目标(chooseRecipient):
<?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"
app:startDestination="@id/mainFragment">
<fragment
android:id="@+id/mainFragment"
android:name="com.example.cashdog.cashdog.MainFragment"
android:label="fragment_main"
tools:layout="@layout/fragment_main" >
<action
android:id="@+id/action_mainFragment_to_chooseRecipient"
app:destination="@id/sendMoneyGraph" />
<action
android:id="@+id/action_mainFragment_to_viewBalanceFragment"
app:destination="@id/viewBalanceFragment" />
</fragment>
<fragment
android:id="@+id/viewBalanceFragment"
android:name="com.example.cashdog.cashdog.ViewBalanceFragment"
android:label="fragment_view_balance"
tools:layout="@layout/fragment_view_balance" />
<navigation android:id="@+id/sendMoneyGraph" app:startDestination="@id/chooseRecipient">
<fragment
android:id="@+id/chooseRecipient"
android:name="com.example.cashdog.cashdog.ChooseRecipient"
android:label="fragment_choose_recipient"
tools:layout="@layout/fragment_choose_recipient">
<action
android:id="@+id/action_chooseRecipient_to_chooseAmountFragment"
app:destination="@id/chooseAmountFragment" />
</fragment>
<fragment
android:id="@+id/chooseAmountFragment"
android:name="com.example.cashdog.cashdog.ChooseAmountFragment"
android:label="fragment_choose_amount"
tools:layout="@layout/fragment_choose_amount" />
</navigation>
</navigation>
- 在您的代码中,将连接根图的操作的资源ID传递给嵌套图:
Navigation.findNavController(view).navigate(R.id.action_mainFragment_to_sendMoneyGraph);
十二、使用<include>引用其他导航图
在导航图中,您可以使用&lt; include&gt;来引用其他图表。 虽然这在功能上与使用嵌套图相同,但&lt; include&gt; 允许您使用其他项目模块或库项目中的图形,如下例所示:
<include app:graph="@navigation/included_graph"/>
<include>包含一个属性app:graph,指向要包含的图形资源。 不允许其他属性。
十三、为目标创建深层链接
在Android中,深层链接是指向应用中特定目标的URI。 当您希望将用户发送到特定目的地以在您的应用中执行某项任务时,这些URI非常有用,例如发送资金流,允许用户快速汇款给某人。
为目标分配深层链接
要在导航图中为目标分配深层链接,请执行以下操作:
- 从图表编辑器中,选择深层链接的目标。
- 单击“属性”面板的“深层链接”部分中的+。 将出现“添加深层链接”对话框。
- 在URI字段中键入URI,例如“
www.cashdog.com/sendmoney
”,它表示应用程序中发送货币嵌套图的起始目的地。
请注意以下事项:
- 没有方案的URI被假定为http和https。 例如,
www.cashdog.com
与http://www.cashdog.com
和https://www.cashdog.com
相匹配。 - 占位符以
{placeholder_name}
的形式匹配1个或多个字符。 占位符的String值在参数Bundle中可用,并带有相同名称的键。 例如,http://www.example.com/users/ {id}
与http://www.example.com/users/4
相匹配。 -
.*
通配符可用于匹配0个或多个字符。
- (可选)选中“自动验证”以要求Google验证您是URI的所有者。 有关更多信息,请参阅验证Android应用程序链接。
- 单击添加。 所选目标上方会显示一个链接图标,表示该目标具有深层链接。
- 单击“文本”选项卡以切换到XML视图。 已将嵌套的深层链接元素添加到目标:
<deepLink app:uri="https://cashdog.com/sendmoney"/>
当用户使用深层链接目标中的“后退”按钮时,他们会导航回导航堆栈,就像他们从应用程序的入口点进入您的应用程序一样。
为深层链接添加intent过滤器
您必须添加manifest.xml文件以在您的应用中启用深层链接:
- 对于Android Studio 3.0和3.1,您必须手动添加intent-filter元素。 有关更多信息,请参阅创建应用程序内容的深层链接。
- 对于Android Studio 3.2+,您可以向活动元素添加nav-graph元素:
<activity name=".MainActivity">
<nav-graph android:value="@navigation/main_nav" />
</activity>
作为清单合并构建步骤的一部分,此元素将替换为匹配导航图中所有深层链接所需的生成的<intent-filter>元素。
以编程方式使用NavDeepLinkBuilder创建深层链接
您可以使用NavDeepLinkBuilder类构造PendingIntent,将用户带到特定目标。
触发此深层链接时,将清除任务后台堆栈并替换为深层链接目标。 嵌套图形时,每个嵌套级别的起始目标(即层次结构中每个<navigation>元素的起始目标)也会添加到堆栈中。
您可以使用NavDeepLinkBuilder(Context)
直接构造PendingIntent,如下例所示。 请注意,如果提供的上下文不是Activity,则构造函数使用PackageManager.getLaunchIntentForPackage()
作为要启动的默认活动(如果可用)。
PendingIntent pendingIntent = new NavDeepLinkBuilder(context)
.setGraph(R.navigation.mobile_navigation)
.setDestination(R.id.android)
.setArguments(args)
.createPendingIntent();
注意:如果您有现有的NavController,还可以通过
NavController.createDeepLink()
创建深层链接。
十四、在目的地之间创建过渡
导航架构组件提供了在目标之间轻松添加转换(例如淡入和淡出)的功能。 要添加转换:
- 创建动画资源文件。导航架构组件支持属性和视图动画。有关更多信息,请参阅动画资源。
- 在“曲线图编辑器”中,单击应进行过渡的操作。
- 在“属性”面板的“过渡”部分中,单击“输入”旁边的向下箭头。将显示项目中的转换列表。
- 选择用户进入目的地时发生的转换。
- 在“属性”面板的“过渡”部分中,单击“退出”旁边的向下箭头。将显示项目中的转换列表。
- 选择用户退出目标时发生的转换。
- 单击“文本”选项卡以切换到XML文本视图。转换的XML出现在步骤2中指定的操作的action元素中。该操作嵌入在转换发生之前处于活动状态的目标的XML中。在以下示例中,defineAmountFragment是活动目标,它包含具有过渡动画的操作:
<fragment
android:id="@+id/specifyAmountFragment"
android:name="com.example.buybuddy.buybuddy.SpecifyAmountFragment"
android:label="fragment_specify_amount"
tools:layout="@layout/fragment_specify_amount">
<action
android:id="@+id/confirmationAction"
app:destination="@id/confirmationFragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
</fragment>
在此示例中,我们在移动到目标时会发生转换(enterAnim和exitAnim以及退出该目标时(popEnterAnim和popExitAnim))。
在目标之间添加共享元素转换
除了过渡动画之外,导航架构组件还支持在目标之间添加共享元素过渡。
与动画不同,共享元素转换是以编程方式提供的,而不是通过导航XML文件提供的,因为它们需要引用您希望包含在共享元素转换中的View实例。
每种类型的目标都通过Navigator.Extras接口的子类实现此编程API。 Extras被传递给navigate()的调用。
片段目标共享元素转换
FragmentNavigator.Extras类允许您将共享元素附加到对Fragment目标的navigate()调用,如下例所示:
FragmentNavigator.Extras extras = new FragmentNavigator.Extras.Builder()
.addSharedElement(imageView, "header_image")
.addSharedElement(titleView, "header_title")
.build();
Navigation.findNavController(view).navigate(R.id.details,
null, // Bundle of args
null, // NavOptions
extras);
活动目标共享元素转换
活动依赖于ActivityOptionsCompat来控制共享元素转换,详见使用共享元素文档启动活动,如下例所示:
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,
Pair.create(imageView, "header_image"),
Pair.create(titleView, "header_title"));
ActivityNavigator.Extras extras = new ActivityNavigator.Extras(options);
Navigation.findNavController(view).navigate(R.id.details,
null, // Bundle of args
null, // NavOptions
extras);