我们可以将Android Jetpack Navigation组件与设置偏好一起使用吗?

12

是否可能使用Android Jetpack Navigation组件导航到设置偏好的片段?我有一个带有多个嵌套Preference片段的设置屏幕。我想知道是否可以使用Android Jetpack Navigation组件来简化我的任务?


可能是重复的问题,与 https://dev59.com/1FQJ5IYBdhLWcg3w05VM 相关。 - coroutineDispatcher
我想使用导航组件在我的设置活动中导航到嵌套的片段。 - Mervin Hemaraju
2个回答

6
谷歌的文档说明,偏好设置的分层嵌套现已废弃,推荐使用片段内导航;也就是说,结构<PreferencesScreen> ... <PreferencesScreen ...> ... </PreferenceScreen> ... </PreferenceScreen>不再适用。
文档建议将嵌套的<PreferenceScreen/>替换为一个偏好设置,并设置app:fragment属性,因此
<xml ...>
<PreferencesScreen ...>
    <Preference
        android:title="Title"
        app:fragment="TLD.DOMAIN.PACKAGE.preferences.SUBPreferenceFragment"
        app:destination="@+id/SUBPreferenceFragment" # Not supported by Schema
        android:summary="Summary"/> 
</PreferenceScreen>

注意:如果允许app:destination="@+id/SUBPreferenceFragment"来标识导航目的地将非常方便;我只需要从导航图的XML文件中复制app:destination

然后,通过引用此preference.fragment,可以按照以下方式在PREFERENCEFramgent之间导航,文档中有说明。

class Activity : AppCompatActivity(),
                  // Preferences Interface
                  PreferenceFragmentCompat.OnPreferenceStartFragmentCallback
{
    ...
    override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, preference: Preference): Boolean 
    {
        // Instantiate the new Fragment
        val args = preference.extras
        val fragment = supportFragmentManager.fragmentFactory.instantiate(
            classLoader,
            preference.fragment)
        fragment.arguments = args
        fragment.setTargetFragment(caller, 0)
        // Replace the existing Fragment with the new Fragment
        supportFragmentManager.beginTransaction()
            .replace(R.id.FRAGMENT, fragment)
            .addToBackStack(null)
            .commit()
       return true
    }
    ...
}

然而,有一个小问题!在普通的活动中,R.id.FRAGMENT 表示活动视图中的占位符,您可以在其中将主要片段交换进出。当使用导航时,R.id.FRAGMENT 映射到 R.id.NAVIGATION,上面的代码会用首选项替换整个导航片段。对于使用导航的活动,需要进行重新制定。

class Activity : AppCompatActivity(),
                  // Preferences Interface
                  PreferenceFragmentCompat.OnPreferenceStartFragmentCallback
{
    ...
    override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, preference: Preference): Boolean {
        // Retrieve the navigation controller
        val navctrl = findNavController(R.id.navigation)
        // Identify the Navigation Destination
        val navDestination = navctrl.graph.find { target -> preference.fragment.endsWith(target.label?:"") } 
        // Navigate to the desired destination
        navDestination?.let { target -> navctrl.navigate(target.id) }
    }
    ...
}

虽然这个方法能够工作,但是我对于决定 navDestination 的那一行代码感到有些怀疑。如果您有更好的写法,可以编辑问题或者留下评论,以便我更新答案。val navDestination = navctrl.graph.find { target -> preference.fragment.endsWith(target.label?:"") }


1

是的,您可以在“偏好设置”片段中使用导航组件。

我也有一个主偏好设置片段,其中包含多个嵌套片段。对我而言,最好的方法是仅在偏好设置片段内导航,而无需任何活动。因此,我创建了onPreferenceClickListeners,并像从普通片段导航一样进行导航。

findPreference(getString(R.string.PREF_GN_BUTTON_MAIN)).setOnPreferenceClickListener(preference5 -> {
            Navigation.findNavController(requireView()).navigate(R.id.another_settings_fragment);
            return true;
        });

这种方式的优点是,您可以使用gradle插件Safe args在不同目标之间导航。因此,它比仅使用像Carel这样的id更安全。
我尝试在我的活动中覆盖onPreferenceStartFragment,但我没有看到任何优点。我使用单个Activity架构。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接