android 导航框架,【译】Android Jetpack 架构导航组件之Navigation

导航架构组件简化了App内不同目标的导航实现。一个目标即是App内一个特定的屏幕。导航架构组件默认包含了对fragments和Activities的支持,但是你也可以添加对新类型目标的支持。一系列的目标集合组成了app的导航图。

另外,导航图内不同目标的连接被称作"actions"。图1展示了示例app内一个假设的导航图表现,包含了6个目标,由5个actions连接。

5bfb09064efa?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

图1 navigation-graph.png

Set up nagivation in a project

在你创建一个导航图之前,你必须在你的工程内配置导航架构组件。以下是具体步骤:

在你的app或者模块的build.gradle文件内天井Navigation Architecture Component。点击Adding components to your project查看更多。

在工程窗口,右击 res 目录,选择 New > Android resource file。显示New Resource对话框。

输入资源名称在File name栏目,比如“nav_graph”。

选择Navigation在Resource type下拉列表。

点击 OK。出现以下项目:

a. 一个 nagivation 资源目录在res目录下创建。

b. 一个nav_graph.xml文件在navigation目录下创建。

c. nav_graph.xml文件将在Navigation Editor中打开。这个文件包含了你的导航图。

点击Texttab可以打开或者关闭text View。空导航图如下:

点击 Design返回导航编辑器。

Tour The Navigation Editor

Note: The Navigation Editor是在Android Studio的Canary Build中默认开启的。为了在Beta,Release Candidate和Stable Builds 中启用,在Mac上点击File > Settings(Android Studio > Preferences),在左侧面板选择Experimentalcategory,选择Enable Navigation Editor,最后重启Android Studio。

5bfb09064efa?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

图2 navigation-editor.png

在导航编辑器,你可以快速地构建导航图,不需要手动构建graph’s xml文件。按照图2显示的,导航编辑器分为三个部分。

1. 目标列表-罗列当前导航编辑器内所有目标。

2. 图编辑器-包含导航图内所有虚拟目标。

3. 属性编辑器-包含目标属性和导航图内的actions。

Identify destinations

为你的app验证目标是创建导航图的第一部。你可以创建一个空目标或者在一个已经存在的工程内为fragments和Acitvities创建目标。

Note:导航架构组件是为一个activity内包含多个fragment的场景而设计的。主activity拥有导航图。在一个拥有众多activity目标的app内,每一个附加的activity都拥有自己的导航图。修改一个activity到主导航将在之后的文档进行讨论。

请参照一下步骤验证app内目标:

在图编辑器,点击** New Destination。New Destination** 显示。

点击Create blank destination或者点击一个fragment或者activity。会出现新的Android Component 对话框。

在Fragment Name字段输入名字。这个名字是fragment的类的名字。

在Fragment layout Name字段输入一个名字。这个名字是fragment布局文件的名字。

点击完成,在图标编辑器的目标列表出现一个目标,出现以下现象:

如果你创建一个空白的目标,在图标编辑器出现一个空白的一个“Hello blank fragment” 的信息的目标,如果你点击了一个Fragment或者Activity,图标编辑器会显示对应的布局。

一个fragment子类将会被创建,名字在第三步被指定。

一个资源文件会被创建,名字在第四步被指定。

图3 展示了一个空白的已经存在的目标。

5bfb09064efa?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

图3 navigation-newexisting.png

点击高亮显示新插入的目标。在属性面板显示以下属性。

在类型字段显示“fragment”或者“activity”,表示目标是否执行了fragment或者activity。

标签字段表示了目标布局文件的名字;

ID字段表示了目标的ID,用来在代码中被引用;

类字段表示了引用的目标的类名;

点击Text 进入xml视图,XML现在包含id,name(class name),label和layout属性,基于已经存在的类和布局文件的名字。

xmlns:tools="http://schemas.android.com/tools"

xmlns:android="http://schemas.android.com/apk/res/android"

app:startDestination="@id/blankFragment">

android:id="@+id/blankFragment"

android:name="com.example.cashdog.cashdog.BlankFragment"

android:label="Blank"

tools:layout="@layout/fragment_blank" />

Note:XML布局startDestination 表示一个空目标的Id,(app:startDestination="@+id/fragment")。查询更多关于startDestination信息请点击Designate a screen as the start destination。

Connect destinations

xmlns:tools="http://schemas.android.com/tools"

xmlns:android="http://schemas.android.com/apk/res/android"

app:startDestination="@id/blankFragment">

android:id="@+id/blankFragment"

android:name="com.example.cashdog.cashdog.BlankFragment"

android:label="fragment_blank"

tools:layout="@layout/fragment_blank" />

android:id="@+id/blankFragment2"

android:name="com.example.cashdog.cashdog.BlankFragment2"

android:label="Blank2"

tools:layout="@layout/fragment_blank_fragment2" />

通过action连接不同的destination:

1、在Graph Editor,当鼠标浮动在destination的右边缘时会显示一个圈;

2、点击并且拖动圆圈到另一个destination,一条线将会关联起两个destination;

5bfb09064efa?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

图5navigation-connected.png

3、点击高亮箭头,属性面板显示以下属性:

类型字段包含“Action”;

ID字段表示了系统为action指定的ID;

Destination字段表示了目标Activity或者Fragment;

4、代码展示:

xmlns:tools="http://schemas.android.com/tools"

xmlns:android="http://schemas.android.com/apk/res/android"

app:startDestination="@id/blankFragment">

android:id="@+id/blankFragment"

android:name="com.example.cashdog.cashdog.BlankFragment"

android:label="fragment_blank"

tools:layout="@layout/fragment_blank" >

android:id="@+id/action_blankFragment_to_blankFragment2"

app:destination="@id/blankFragment2" />

android:id="@+id/blankFragment2"

android:name="com.example.cashdog.cashdog.BlankFragment2"

android:label="fragment_blank_fragment2"

tools:layout="@layout/fragment_blank_fragment2" />

Designate a screen as the start destination

Graph Editor中,进入app的第一个Destination会有一个house的icon。通过一下步骤可以将另外一个Destination指定为启动Destination。

1、点击高亮显示某个Destination;

2、点击属性面板的Set Start Destination即可完成设置;

Modify an activity to host navigation

一个Activity通过NavHost的实现类来持有app的导航。NavHost是一个空的View,因此Destinations会根据用户的导航被交换进或者退出。

Navigation Architecture Component 的默认的NavHost的实现是NavHostFragment。

在你包含了NavHost之后,你必须使用navGraph属性将NavHostFragment和Navigation graph关联起来。下面是代码示例:

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

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"

/>

上述例子的app:defaultNavHost="true"属性可以确保NavHostFragment可以拦截系统的回退事件。你也可以重写AppCompatActivity.onSupportNavigateUp()方法并且调用NavController.navigateUp方法:

@Override

public boolean onSupportNavigateUp() {

return Navigation.findNavController(this, R.id.nav_host_fragment).navigateUp();

}

Create the NavHostFragment programmatically

你可以使用NavHostFragment.create()

编码创建NavHostFragment ,关联一个graph资源,如下所示:

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

Tie destinations to UI widgets

通过NavController

实现对Destination的导航。通过以下静态方法获取NavController示例:

viewTransactionsButton.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

Navigation.findNavController(view).navigate(R.id.viewTransactionsAction);

}

});

Android 系统维护了一个back stack来表示最近访问的destination。

在app启动得时候,第一个destination会被放入栈里面。每一次调用navigate()

都会放入另外一个destination在栈的顶部。相反的,调用NavController.navigateUp()

和NavController.popBackStack()

方法,从栈里弹出顶部的destination。对于按钮,你可以使用Navigation

类的 createNavigateOnClickListener() 方法来很方便地去导航到destination。

button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.next_fragment, null));

Tie destinations to menu-driven UI components

通过为destination、navigation drawer和overflow menu设置相同的Id来将destination和navigation drawer或者overflow menu关联起来。以下代码片段显示了id为details_page_fragment的destination:

android:label="@string/details"

android:name="com.example.android.myapp.DetailsFragment" />

以下代码片段表示了如何关联fragment destination 和navigation drawer中的menu item,比如( menu_nav_drawer.xml)。

android:id="@id/details_page_fragment"

android:icon="@drawable/ic_details"

android:title="@string/details" />

以下XML表示了如果把destination和overflow menu 关联的细节:

android:id="@id/details_page_fragment"

android:icon="@drawable/ic_details"

android:title="@string/details"

android:menuCategory:"secondary" />

Navigation Architecture Component 包含了一个NavigationUI

类。这个类的多个静态方法都可以用来关联 menu item 和 navigation destination。以下代码表示了如果使用setupWithNavController()

方法去关联 menu item 到Navigation View。

NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);

NavigationUI.setupWithNavController(navigationView, navController);

使用NavigationUI

去设置menu 驱动的导航组件是很有必要的,因为这样可以同步这些UI元素地改变到NavController。

Pass data between destinations

两种方式在不同的destination之间传递数据:使用Bundle

对象或者通过Gradle插件类型安全得传递数据。遵照以下步骤在destinations之间使用Bundle对象传递数据。如果你想使用Gradle,请遵照Pass data between destinations in a type-safe way

的介绍。

1、在Graph Editor,点击接受参数的destination。该destination会高亮。

2、在属性面板的参数部分点击 Add(+),会显示空名字和默认值字段。

3、在名字字段双击输入参数名字。

4、按压Tab,输入参数的默认值。

5、点击上述destination的action。参数的默认值应该包含你新增的参数。

6、点击Text去切换XML View。一个参数元素,包含名字和默认值属性,已经被添加到该destination。

android:id="@+id/confirmationFragment"

android:name="com.example.buybuddy.buybuddy.ConfirmationFragment"

android:label="fragment_confirmation"

tools:layout="@layout/fragment_confirmation">

当你使用safeargs plugin,会为action,destinations的接受者和发送者创建简单对象和构造类。这些类是:

一个类为action源起的destination,后缀“Directions”。因此,如果起始的fragment叫做SpecifyAmountFragment,那么生成的类就叫做SpecifyAmountFragmentDirections。这个类有一个以传递参数的action来命名,去绑定参数,比如confirmationAction()。

一个匿名内部类,名字基于传递参数的action。如果传递的action叫做confirmationAction,类就被命名为ConfirmationAciton。

一个类用于接受destination,后缀Args,所以,如果destination fragment叫做ComfirmationFragment,生成的类就叫做ConfirmationFragmentArgs。使用这个类的fromBundle()方法获取参数。

示例代码:

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

}

@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 + "")

}

Group destinations into a nested navigation graph

在navigation graph内,可以把一些相关的destination是分组为sub-graph,如果包含sub-graph的是root-graph,那么这个sub-graph被称作“nestedgraph”,Nestedgraph在组织和重用App UI的模块上是很有用的,比如登录流程。

和root graph一样,nested graph必须也要有一个启动的destination作为唯一的标识。nested graph封装了它的destinations。nested graph外部,root graph之内的destination只能通过root graph的启动destination访问nested graph。图6 展示了一个simple money transfer app的navigation graph。这个graph有两个流程:转钱流程和余额流程。

5bfb09064efa?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

图6 navigation-pre-nestedgraph.png

把destinations分组为nested graph:

1、在graph editor,按住shift点击需要加入nested graph的destination,该destination高亮。

2、打开菜单选择Move to Nested Graph > New Graph,如图7.

5bfb09064efa?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

图7navigation-nestedgraph.png

3、点击高亮nested graph,属性面板显示如下:

Type字段显示“Nested Graph”。

Id字段是系统为nested graph指定的。Id用来在代码中引用这个nested graph。

4、双击nested graph查看内部的destinations。

5、在destinations列表,点击root返回root graph。

6、点击Text进入XML视图。

xmlns:tools="http://schemas.android.com/tools"

xmlns:android="http://schemas.android.com/apk/res/android"

app:startDestination="@id/mainFragment">

android:id="@+id/mainFragment"

android:name="com.example.cashdog.cashdog.MainFragment"

android:label="fragment_main"

tools:layout="@layout/fragment_main" >

android:id="@+id/action_mainFragment_to_chooseRecipient"

app:destination="@id/sendMoneyGraph" />

android:id="@+id/action_mainFragment_to_viewBalanceFragment"

app:destination="@id/viewBalanceFragment" />

android:id="@+id/viewBalanceFragment"

android:name="com.example.cashdog.cashdog.ViewBalanceFragment"

android:label="fragment_view_balance"

tools:layout="@layout/fragment_view_balance" />

android:id="@+id/chooseRecipient"

android:name="com.example.cashdog.cashdog.ChooseRecipient"

android:label="fragment_choose_recipient"

tools:layout="@layout/fragment_choose_recipient">

android:id="@+id/action_chooseRecipient_to_chooseAmountFragment"

app:destination="@id/chooseAmountFragment" />

android:id="@+id/chooseAmountFragment"

android:name="com.example.cashdog.cashdog.ChooseAmountFragment"

android:label="fragment_choose_amount"

tools:layout="@layout/fragment_choose_amount" />

7、在你的代码里,使用action id来关联root graph 和 nested graph。

Navigation.findNavController(view).navigate(R.id.action_mainFragment_to_sendMoneyGraph);

Reference other navigation graphs using

在 navigation graph内,可以通过引用其它navigation graph,其等价于使用nested graph。以此使用其它module或者library中的navigation。

只有一个app:graph属性,且不允许其它任何属性。

Create a deep link for a destination

Add an intent filter for a deep link

Create a transition between destinations

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值