navigation的使用,网上资料很多,就不弄了,有空再补充。
随时补充
如下代码
<?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"
xmlns:tools="http://schemas.android.com/tools"
app:startDestination="@id/fragmentHome">
<action
android:id="@+id/go_StepOne"
app:destination="@id/fragmentStepOne" />
<fragment
android:id="@+id/fragmentHome"
android:name="com.charliesong.demo0327.navigation.FragmentHome"
android:label="FragmentHome"
tools:layout="@layout/nav_fragment_home">
</fragment>
<fragment
android:id="@+id/fragmentStepOne"
android:name="com.charliesong.demo0327.navigation.FragmentStepOne"
android:label="FragmentStepOne"
tools:layout="@layout/nav_fragment_step_one">
<argument
android:name="title"
android:defaultValue="just test" />
<argument
android:name="title2"
android:defaultValue="just test2" />
<action
android:id="@+id/fragmentStepOne1"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right"
app:destination="@id/fragmentStepTwo" />
</fragment>
<fragment
android:id="@+id/fragmentStepOne1"
android:name="com.charliesong.demo0327.navigation.FragmentStepOne"
android:label="FragmentStepOne"
tools:layout="@layout/nav_fragment_step_one">
<action
android:id="@+id/go_StepTwo"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right"
app:destination="@id/fragmentStepTwo" />
</fragment>
<fragment
android:id="@+id/fragmentStepTwo"
android:name="com.charliesong.demo0327.navigation.FragmentStepTwo"
android:label="FragmentStepTwo"
tools:layout="@layout/nav_fragment_step_two">
<action
android:id="@+id/go_StepOne"
app:destination="@id/fragmentStepOne" />
<action
android:id="@+id/go_home"
app:popUpTo="@id/fragmentHome"/>
</fragment>
</navigation>
说明:action标签可以写在fragment外边,也可以是里边,区别在于。
写在外边,这个id哪里都可以用。写在fragment里边的,只有这个fragment可以用,其他fragment用这个action的id就会报错。
问题:
因为我基类里写了如下的代码,也就是使用了toolbar的后退键
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when(item.itemId){
android.R.id.home->{
onBackPressed()
//忘了加 return true了,所以引发了下边的执行了2次后退操作
}
}
return super.onOptionsItemSelected(item)
}
而现在加了navigation以后,我们的fragment也要拦截后退键的
override fun onSupportNavigateUp(): Boolean = findNavController(my_nav_host_fragment).navigateUp()
然后就发现,点击手机上的物理后退键是没有任何问题了。fragment是正常的一次后退一个。
可点击toolbar上的后退箭头,就发现一次退了至少2个fragment。然后去看下了代码
如下AppCompatActivity里,果然也处理 android.R.id.home,这等于处理了2次。
public final boolean onMenuItemSelected(int featureId, android.view.MenuItem item) {
if (super.onMenuItemSelected(featureId, item)) {
//super的代码在下边,由于忘了写return true了,所以后退执行了2次。
return true;
}
final ActionBar ab = getSupportActionBar();
if (item.getItemId() == android.R.id.home && ab != null &&
(ab.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
return onSupportNavigateUp();
}
return false;
}
再看下Activity里的代码
public boolean onMenuItemSelected(int featureId, MenuItem item) {
CharSequence titleCondensed = item.getTitleCondensed();
switch (featureId) {
case Window.FEATURE_OPTIONS_PANEL:
// Put event logging here so it gets called even if subclass
// doesn't call through to superclass's implmeentation of each
// of these methods below
if(titleCondensed != null) {
EventLog.writeEvent(50000, 0, titleCondensed.toString());
}
if (onOptionsItemSelected(item)) {
return true;
}
首先Navigation这个工具类
公开的静态方法就是下边这几个
image.png
然后我们看下获取
可以看到,是对我们传如的view,读取getTag来得到的,如果没有,就找view的parent。
需要注意的是,如果没找到,它就直接抛出异常了。所以传的view要确保有
image.png
然后看下设置,就是把controller设置为tag
public static void setViewNavController(@NonNull View view,
@Nullable NavController controller) {
view.setTag(R.id.nav_controller_view_tag, controller);
}
看看哪里设置的,就是系统的NavHostFragment
image.png
我们在布局里一般这么写的,所以如上图所注释的,我们的controller就是设置给了这个fragment的View拉。
<fragment
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/mobile_navigation"
app:defaultNavHost="true"
/>
另外获取controller也可以通过如下方法
NavHostFragment里有
public static NavController findNavController(@NonNull Fragment fragment)
或者
public NavController getNavController() {
if (mNavController == null) {
throw new IllegalStateException("NavController is not available before onCreate()");
}
return mNavController;
}
需要注意的是controller是在NavHostFragment的onCreate方法里创建的,所以在这个生命周期之前获取不到的。
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Context context = getContext();
mNavController = new NavController(context);
mNavController.getNavigatorProvider().addNavigator(createFragmentNavigator());
网友评论