感谢 bottomNavigationView,我使用NavController在4个不同的片段之间导航。
在其中一个片段(ChallengesFragment)中,我有一个inner_fragment(nav_host_fragment_challenges),但是当我尝试在这个inner_fragment中导航时,它不起作用。
下面是我的MainActivity.kt:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.navigation_bar)
bottomNavigationView.setupWithNavController(navController)
}
}
我的ChallengesFragment.kt(承载inner_fragment的fragment):
class ChallengesFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val inflater_challenges = LayoutInflater.from(ContextThemeWrapper(context, R.style.Theme_challenges))
val view = inflater_challenges.inflate(R.layout.fragment_challenges, container, false)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val challengesNavHostFragment = childFragmentManager.findFragmentById(R.id.nav_host_fragment_challenges) as NavHostFragment
//val challengesNavHostFragment = requireActivity().supportFragmentManager.findFragmentById(R.id.nav_host_fragment_challenges) as NavHostFragment
val challengesNavController = challengesNavHostFragment.navController
}
}
我的问题:val challengesNavHostFragment = childFragmentManager.findFragmentById(R.id.nav_host_fragment_challenges) as NavHostFragment
给予我这个错误:java.lang.NullPointerException:null不能强制转换为非null类型androidx.navigation.fragment.NavHostFragment
所以我尝试了val challengesNavHostFragment = requireActivity().supportFragmentManager.findFragmentById(R.id.nav_host_fragment_challenges) as NavHostFragment
(代码中带有//的行),它一开始工作,但当我离开 ChallengesFragment 然后回来时,inner_fragment不再显示...
我认为应该使用childFragmentManager,但如果你有一个解决方案可以与其他东西一起使用,我会接受它。
我的fragment_challenges.xml的FragmentContainerView:
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment_challenges"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/challenge_topbar"
app:navGraph="@navigation/nav_graph_challenges"
app:defaultNavHost="false"
tools:layout="@layout/fragment_quests" />
如有需要,我的nav_graph.xml:
<?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"
android:id="@+id/nav_graph"
app:startDestination="@id/homeFragment">
<fragment
android:id="@+id/profileFragment"
android:name="fr.apgames.veuja.fragments.ProfileFragment"
android:label="ProfileFragment" />
<fragment
android:id="@+id/calendarFragment"
android:name="fr.apgames.veuja.fragments.CalendarFragment"
android:label="CalendarFragment" />
<fragment
android:id="@+id/challengesFragment"
android:name="fr.apgames.veuja.fragments.ChallengesFragment"
android:label="ChallengesFragment" />
<fragment
android:id="@+id/homeFragment"
android:name="fr.apgames.veuja.fragments.HomeFragment"
android:label="HomeFragment" />
<include app:graph="@navigation/nav_graph_challenges" />
</navigation>
最后是我的nav_graph_challenges.xml:
<?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"
android:id="@+id/nav_graph_challenges"
app:startDestination="@id/challengesQuestsFragment">
<fragment
android:id="@+id/challengesMyStoryFragment"
android:name="fr.apgames.veuja.fragments.ChallengesMyStoryFragment"
android:label="ChallengesMyStoryFragment" >
<action
android:id="@+id/action_challengesMyStoryFragment_to_challengesQuestsFragment"
app:destination="@id/challengesQuestsFragment" />
</fragment>
<fragment
android:id="@+id/challengesQuestsFragment"
android:name="fr.apgames.veuja.fragments.ChallengesQuestsFragment"
android:label="ChallengesQuestsFragment" >
<action
android:id="@+id/action_challengesQuestsFragment_to_challengesMyStoryFragment"
app:destination="@id/challengesMyStoryFragment" />
</fragment>
</navigation>
- 如果你能解释一下NavController是如何工作的,因为正如你所看到的,我有点迷失了方向……谢谢
1条答案
按热度按时间91zkwejq1#
传入
onCreateView
的inflater
不是从LayoutInflater.from(context)
得到的LayoutInflater
-它知道你在哪个片段中。这就是FragmentContainerView
如何知道它需要被添加为您所在的Fragment的子片段(如果您查看source code,您将看到FragmentContainerView
的特殊大小写)。所以当你使用
您正在创建一个完全不知道您所在片段的LayoutInflater。这就是为什么你的片段(应该是一个子片段)实际上被添加到Activity的
FragmentManager
中。这样做的副作用是,实际上并没有将片段嵌套在另一个片段中,从而导致当父片段再次可见时,片段不会重新出现(因为从FragmentManager的Angular 来看,它们是完全独立的片段)。如果您专门为片段启用了StrictMode,这类问题将触发
WrongNestedHierarchyViolation
,因为没有正确嵌套片段会产生负面影响。因此,您应该:
1.使用
onCreateView
传递给您的inflater
1.在
fragment_challenges.xml
XML文件中使用android:theme="@style/Theme.challenges"
为层次结构中该部分的所有内容设置主题,而不是使用ContextThemeWrapper
。