Android - 如何使用导航处理来自父片段的嵌套图片段?
Androidx - How to handle Nested Graph's fragments from parent fragment using Navigation?
场景如下:-
我有一个 Main Activity,它默认有根 NavGraph 和加载片段 A。如果我从片段 A 移动到片段 B,其中有子片段和 TabLayout,那么用户可以在其中切换片段,为此我在片段 B 中为子片段创建了一个新的嵌套图。当我从片段移动时A 到 Fragment B,我能够在我的子 Fragment 中显示 Fragment C,因为我在我的嵌套图表中将开始目标设置为 Fragment C。
***root Navigation Graph***
<?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"
android:id="@+id/navigation_graph"
app:startDestination="@id/fragmentC">
<fragment
android:id="@+id/FragmentA"
android:name="com.myapp.fragment.FragmentA"
android:label="Fragment A"
tools:layout="@layout/fragment_A">
<action
android:id="@+id/action_fragmentA_to_fragmentB"
app:destination="@id/fragmentB" />
</fragment>
<fragment
android:id="@+id/fragmentB"
android:name="com.myapp.fragment.FragmentB"
android:label="FragmentB"
tools:layout="@layout/fragment_B">
<action
android:id="@+id/action_fragmentB_to_second_graph"
app:destination="@id/navigation_graph2" />
</fragment>
<include app:graph="@navigation/navigation_graph2" />
</navigation>
***Nested Navigation Graph***
<?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"
android:id="@+id/navigation_graph2"
app:startDestination="@id/FragmentC">
<fragment android:id="@+id/FragmentC"
android:name="com.myapp.fragment.FragmentC"
android:label="Fragment C"
tools:layout="@layout/fragment_C">
<action
android:id="@+id/action_fragmentC_fragmentD"
app:destination="@id/FragmentD" />
</fragment>
<fragment android:id="@+id/FragmentD"
android:name="com.myapp.fragment.FragmentD"
android:label="Fragment D"
tools:layout="@layout/fragment_D">
<action
android:id="@+id/action_fragmentD_fragmentC"
app:destination="@id/FragmentC" />
</fragment>
</navigation>
***Inside Fragment B***
public class FragmentB extends BaseFragment<FragmentAssignmentsBinding>
implements TabLayout.OnTabSelectedListener{
NavController nestedNavController;
@Override
public int getLayoutId() {
return R.layout.fragment_assignments;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
if(getFragmentDataBinding()==null)
return;
nestedNavController = Navigation.findNavController(view);
getFragmentDataBinding().myTabLayout.addOnTabSelectedListener(this);
}
@Override
public void onTabSelected(TabLayout.Tab tab) {
switch (tab.getPosition()) {
case 0:
//***Here how to handle the nested graph Fragment Action ?***
nestedNavController.navigate(R.id. action_fragmentC_fragmentD);
break;
case 1:
nestedNavController.navigate(R.id. action_fragmentD_fragmentC);
break;
}
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
}
现在的问题是 -> 从 parentFragment(Fragment B) 点击 Tab A 或 Tab B,我必须访问嵌套的 NavGraph 操作来替换 parentFragment.But 中的片段遇到错误:-
java.lang.IllegalArgumentException: navigation destination
com.myapp:id/action_fragmentC_fragmentD is
unknown to this NavController
任何帮助或指导都会很有帮助。
引用
As per this issue:
Navigation focuses on elements that affect the back stack and tabs do
not affect the back stack - you should continue to manage tabs with a
ViewPager and TabLayout
因此您必须将 ViewPager 与 tablayout 一起使用,而不是嵌套导航图。
请查看 tablayout branch 的工作示例。
在你的片段 B 布局中,你应该有类似的东西:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#1db995">
</android.support.design.widget.TabLayout>
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="355dp"
android:layout_height="455dp"
app:layout_constraintTop_toBottomOf="@+id/tabLayout"
tools:layout_editor_absoluteX="8dp" />
<fragment
android:id="@+id/base_container"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="@dimen/dimen_constraint"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/activity_base_toolbar_main"
app:navGraph="@navigation/navigation_graph2" />
...
public class FragmentB extends ...
...
@Override
public void onTabSelected(TabLayout.Tab tab) {
controller = findNavController(R.id.base_container)
switch (tab.getPosition()) {
case 0:
controller.navigate(R.id.action_fragmentC_fragmentD);
break;
case 1:
controller.navigate(R.id.action_fragmentD_fragmentC);
break;
}
}
...
或者作为解决方法,您可以考虑使用 BottomNavigationView 重现 TabLayout 的相同行为
场景如下:-
我有一个 Main Activity,它默认有根 NavGraph 和加载片段 A。如果我从片段 A 移动到片段 B,其中有子片段和 TabLayout,那么用户可以在其中切换片段,为此我在片段 B 中为子片段创建了一个新的嵌套图。当我从片段移动时A 到 Fragment B,我能够在我的子 Fragment 中显示 Fragment C,因为我在我的嵌套图表中将开始目标设置为 Fragment C。
***root Navigation Graph***
<?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"
android:id="@+id/navigation_graph"
app:startDestination="@id/fragmentC">
<fragment
android:id="@+id/FragmentA"
android:name="com.myapp.fragment.FragmentA"
android:label="Fragment A"
tools:layout="@layout/fragment_A">
<action
android:id="@+id/action_fragmentA_to_fragmentB"
app:destination="@id/fragmentB" />
</fragment>
<fragment
android:id="@+id/fragmentB"
android:name="com.myapp.fragment.FragmentB"
android:label="FragmentB"
tools:layout="@layout/fragment_B">
<action
android:id="@+id/action_fragmentB_to_second_graph"
app:destination="@id/navigation_graph2" />
</fragment>
<include app:graph="@navigation/navigation_graph2" />
</navigation>
***Nested Navigation Graph***
<?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"
android:id="@+id/navigation_graph2"
app:startDestination="@id/FragmentC">
<fragment android:id="@+id/FragmentC"
android:name="com.myapp.fragment.FragmentC"
android:label="Fragment C"
tools:layout="@layout/fragment_C">
<action
android:id="@+id/action_fragmentC_fragmentD"
app:destination="@id/FragmentD" />
</fragment>
<fragment android:id="@+id/FragmentD"
android:name="com.myapp.fragment.FragmentD"
android:label="Fragment D"
tools:layout="@layout/fragment_D">
<action
android:id="@+id/action_fragmentD_fragmentC"
app:destination="@id/FragmentC" />
</fragment>
</navigation>
***Inside Fragment B***
public class FragmentB extends BaseFragment<FragmentAssignmentsBinding>
implements TabLayout.OnTabSelectedListener{
NavController nestedNavController;
@Override
public int getLayoutId() {
return R.layout.fragment_assignments;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
if(getFragmentDataBinding()==null)
return;
nestedNavController = Navigation.findNavController(view);
getFragmentDataBinding().myTabLayout.addOnTabSelectedListener(this);
}
@Override
public void onTabSelected(TabLayout.Tab tab) {
switch (tab.getPosition()) {
case 0:
//***Here how to handle the nested graph Fragment Action ?***
nestedNavController.navigate(R.id. action_fragmentC_fragmentD);
break;
case 1:
nestedNavController.navigate(R.id. action_fragmentD_fragmentC);
break;
}
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
}
现在的问题是 -> 从 parentFragment(Fragment B) 点击 Tab A 或 Tab B,我必须访问嵌套的 NavGraph 操作来替换 parentFragment.But 中的片段遇到错误:-
java.lang.IllegalArgumentException: navigation destination com.myapp:id/action_fragmentC_fragmentD is unknown to this NavController
任何帮助或指导都会很有帮助。
引用
As per this issue:
Navigation focuses on elements that affect the back stack and tabs do not affect the back stack - you should continue to manage tabs with a ViewPager and TabLayout
因此您必须将 ViewPager 与 tablayout 一起使用,而不是嵌套导航图。
请查看 tablayout branch 的工作示例。
在你的片段 B 布局中,你应该有类似的东西:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#1db995">
</android.support.design.widget.TabLayout>
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="355dp"
android:layout_height="455dp"
app:layout_constraintTop_toBottomOf="@+id/tabLayout"
tools:layout_editor_absoluteX="8dp" />
<fragment
android:id="@+id/base_container"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="@dimen/dimen_constraint"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/activity_base_toolbar_main"
app:navGraph="@navigation/navigation_graph2" />
...
public class FragmentB extends ...
...
@Override
public void onTabSelected(TabLayout.Tab tab) {
controller = findNavController(R.id.base_container)
switch (tab.getPosition()) {
case 0:
controller.navigate(R.id.action_fragmentC_fragmentD);
break;
case 1:
controller.navigate(R.id.action_fragmentD_fragmentC);
break;
}
}
...
或者作为解决方法,您可以考虑使用 BottomNavigationView 重现 TabLayout 的相同行为