从官方整了个demo下来,全部kotlin编写,对我这种基本从未用过kotlin的老年选手来说理解真是难搞。
首先按照官方步骤,从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/mobile_navigation"
app:defaultNavHost="true"
/>
android:name=“androidx.navigation.fragment.NavHostFragment” and app:defaultNavHost=“true” connect the system back button to the NavHostFragment
app:navGraph="@navigation/mobile_navigation" associates the NavHostFragment with a navigation graph. This navigation graph specifies all the destinations the user can navigate to, in this NavHostFragment.
官方说明: app:defaultNavHost=true和name=NavHostFragment将返回键接给了NavHostFragment,意思应该就是这样设置之后返回键可以用于fragment回退切换而不是bang掉了activity。
下一句也没什么好说的,连上了一个graph。graph是这套逻辑的核心。
然后进代码块。官方这个demo从界面上看就知道很简单,只包含几个点击事件的处理,所以关注的逻辑基本只有点击事件就够了。
Finally, when a user does something like clicking a button, you need to trigger a navigate command. A special class called the NavController is what triggers the fragment swaps in the NavHostFragment.
来看看官方关于点击事件的说明。
当用户执行诸如单击按钮之类的操作时,需要触发导航命令。一个名为NavController的特殊类触发了NavHostFragment中的片段交换。
val host: NavHostFragment = supportFragmentManager
.findFragmentById(R.id.my_nav_host_fragment) as NavHostFragment? ?: return
// Set up Action Bar
val navController = host.navController
navController.addOnNavigatedListener { _, destination ->
val dest: String = try {
resources.getResourceName(destination.id)
} catch (e: Resources.NotFoundException) {
Integer.toString(destination.id)
}
Toast.makeText(this@MainActivity, "Navigated to $dest",
Toast.LENGTH_SHORT).show()
Log.d("NavigationActivity", "Navigated to $dest")
}
学没学过kotlin不是重点,只要理解中心思想:给你的NavHostFragment对象创建一个Controller→用这个Controller控制。
甚至可以给加载在这个navgraph上的每一次跳转做统一事件。统一监听nb,一瞬间想到了多种玩法。
接着开始进入graph一探究竟
<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"
app:startDestination="@+id/home_dest">
app:startDestination="@+id/home_dest" 指定了起始碎片,顺着id找fragment↓
<fragment
android:id="@+id/home_dest"
android:name="com.example.android.codelabs.navigation.HomeFragment"
android:label="@string/home"
tools:layout="@layout/home_fragment">
没什么好说的,进HomeFragment看看吧。
//TODO STEP 5 - Set an OnClickListener, using Navigation.createNavigateOnClickListener()
val button = view.findViewById<Button>(R.id.navigate_destination_button)
button?.setOnClickListener {
findNavController().navigate(R.id.flow_step_one_dest)
}
//TODO STEP 7.2 - Update the OnClickListener to navigate using an action
view.findViewById<Button>(R.id.navigate_action_button)?.setOnClickListener(
Navigation.createNavigateOnClickListener(R.id.next_action, null)
)
直奔跳转事件,上面涉及到了两种事件触发方法。分别是使用controller控制,和直接绑定actionid
此处的所有id都是指graph里的东西,别傻到去布局文件里找啊。
<fragment
android:id="@+id/flow_step_one_dest"
android:name="com.example.android.codelabs.navigation.FlowStepFragment"
tools:layout="@layout/flow_step_one_fragment">
<fragment
android:id="@+id/home_dest"
android:name="com.example.android.codelabs.navigation.HomeFragment"
android:label="@string/home"
tools:layout="@layout/home_fragment">
<action
android:id="@+id/next_action"
app:destination="@+id/flow_step_one_dest"
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>
The popUpTo attribute is used - this action will pop fragments off of the back-stack until you reach home_dest
清栈就用popUpTo跳完事。
The default transition, as well as other attributes associated with the call, can be overridden by including a set of NavOptions. NavOptions uses a Builder pattern which allows you to override and set only the options you need. There’s also a ktx DSL for NavOptions, which is what you’ll be using.
官方说明。第一眼是不是有人会看不懂,看不懂也不要紧。首先知道这玩意能做动画切换就行了。
val options = navOptions {
anim {
enter = R.anim.slide_in_right
exit = R.anim.slide_out_left
popEnter = R.anim.slide_in_left
popExit = R.anim.slide_out_right
}
}
view.findViewById<Button>(R.id.navigate_destination_button)?.setOnClickListener {
findNavController().navigate(R.id.flow_step_one_dest, null, options)
}
动画怎么写就先不提了。
之前第二种点击事件应该有人已经注意到了。
<action
android:id="@+id/next_action"
app:destination="@+id/flow_step_one_dest"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
谷歌的逻辑真是做的越来越简单清楚nb了。人人可编程指日可待。有种快要被淘汰的危机感。
<fragment
android:id="@+id/flow_step_one_dest"
android:name="com.example.android.codelabs.navigation.FlowStepFragment"
tools:layout="@layout/flow_step_one_fragment">
<argument
android:name="flowStepNumber"
app:argType="integer"
android:defaultValue="1"/>
<action
android:id="@+id/next_action"
app:destination="@+id/flow_step_two_dest">
action>
fragment>
<fragment
android:id="@+id/flow_step_two_dest"
android:name="com.example.android.codelabs.navigation.FlowStepFragment"
tools:layout="@layout/flow_step_two_fragment">
<argument
android:name="flowStepNumber"
app:argType="integer"
android:defaultValue="2"/>
<action
android:id="@+id/next_action"
app:popUpTo="@id/home_dest">
action>
fragment>
这是其中两个碎片布置。argument中的区别只有,defaultValue。
然后去指定的FlowStepFragment里找。
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? {
setHasOptionsMenu(true)
val flowStepNumber = arguments?.getInt("flowStepNumber")
return when (flowStepNumber) {
2 -> inflater.inflate(R.layout.flow_step_two_fragment, container, false)
else -> inflater.inflate(R.layout.flow_step_one_fragment, container, false)
}
}
2填充two,其他填充one。没啥好说的
菜单和deeplink目前项目没需求就暂且不提。
写demo去再慢慢看源码原理。