如何使用新的Android-X API从当前的PreferenceFragment中打开一个新的PreferenceFragment? [英] How to open a new PreferenceFragment from current one, using the new Android-X API?

查看:130
本文介绍了如何使用新的Android-X API从当前的PreferenceFragment中打开一个新的PreferenceFragment?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在早期版本的支持库中,我们可以使用标题,以便具有设置的主菜单屏幕,每个菜单都将打开一个新的设置屏幕(片段).

On previous versions of support library, we could use headers in order to have a main-menu screen of settings, that each would open a new settings screen (fragment) .

现在标题消失了(如 此处 )一段时间,我认为在android-x上情况变得更糟:

Now headers are gone (as written here) for some time, and I think it became worse on android-x :

您要注意的一件事不是首选项标题,您将 完全正确.但是,这并不意味着一个偏好列表 需要跨越一个10英寸的平板电脑屏幕.相反,您的活动可以实现 OnPreferenceStartFragmentCallback(

One thing you’ll note isn’t in here is preference headers and you’d be totally right. However, that doesn’t mean a single list of preferences need to span a 10" tablet screen. Instead, your Activity can implement OnPreferenceStartFragmentCallback (link) to handle preferences with an app:fragment attribute or OnPreferenceStartScreenCallback (link) to handle PreferenceScreen preferences. This allows you to construct a ‘header’ style PreferenceFragmentCompat in one pane and use those callbacks to replace a second pane without working in two separate types of XML files.

问题是,我无法在新的android-x API上使用它们.

Thing is, I fail to use these on the new android-x API.

每个片段都有自己的首选项XML树(在onCreatePreferences中使用setPreferencesFromResource),但是我想出的每个解决方案都没有做任何事情,或者崩溃了.

Each fragment has its own preferences XML tree (using setPreferencesFromResource within onCreatePreferences) , but each solution I've come up with has either done nothing, or crashed.

以可视化的方式表达,这就是我要实现的目标:

To put it in a visual way, this is what I'm trying to achieve :

由于有多个子设置屏幕,因此将所有它们的所有首选项都放在主设置屏幕的一个XML文件中会很麻烦.

Since there are multiple sub settings screens, it would be very messy to have all of the preferences of all of them be put in one XML file of the main settings screen.

我唯一成功的是使用PreferenceScreen来保存应该显示的子屏幕的首选项.

Only thing I've succeeded, is to use the PreferenceScreen to hold the preferences of the sub-screen that's supposed to be shown.

这是一个有效的代码( 此处 )这样的事情:

Here's a working code (project available here) of such a thing :

preferences.xml

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" android:title="Demo">

    <PreferenceScreen
        android:key="screen_preference" android:summary="Shows another screen of preferences"
        android:title="Screen preferenc">

        <CheckBoxPreference
            android:key="next_screen_checkbox_preference"
            android:summary="Preference that is on the next screen but same hierarchy"
            android:title="Toggle preference"/>

    </PreferenceScreen>

</PreferenceScreen>

MainActivity.kt

class MainActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPreferenceStartScreenCallback {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        supportActionBar!!.setDisplayHomeAsUpEnabled(true)
        if (savedInstanceState == null)
            supportFragmentManager.beginTransaction().replace(android.R.id.content, PrefsFragment()).commit()
    }

    override fun onPreferenceStartScreen(caller: PreferenceFragmentCompat, pref: PreferenceScreen): Boolean {
        val f = PrefsFragment()
        val args = Bundle(1)
        args.putString(PreferenceFragmentCompat.ARG_PREFERENCE_ROOT, pref.key)
        f.arguments = args
        supportFragmentManager.beginTransaction().replace(android.R.id.content, f).addToBackStack(null).commit()
        return true
    }

    class PrefsFragment : PreferenceFragmentCompat() {
        override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
            setPreferencesFromResource(R.xml.preferences, rootKey)
        }
    }
}

但是,正如我写的那样,这不是我要尝试做的.我想拥有多个扩展PreferenceFragmentCompat的类,每个类都有其自己的XML文件,该文件将从主类中打开.

But, as I wrote, this is not what I'm trying to do. I want to have multiple classes that extend PreferenceFragmentCompat, each with its own XML file, which will be opened from the main one.

这是我尝试过(但失败了)的事情:

Here are the things I've tried (and failed) :

  1. PreferenceScreen设置一个"android:fragment",以指向新的片段类,类似于标头.这根本什么也没做.

  1. Set a "android:fragment" for the PreferenceScreen, to point to the new fragments classes, similar to headers. This didn't do anything at all.

使用常规首选项并为其单击监听器,这将执行片段处理,如原始代码所示.这导致崩溃,并显示类似具有key screen_preference键的Preference对象不是PreferenceScreen"之类的信息.

Use a normal Preference and have click listener for it, that will do the fragment transaction as shown on the original code. This caused a crash that says something like "Preference object with key screen_preference is not a PreferenceScreen" .

试图避免使用ARG_PREFERENCE_ROOT,但是崩溃与#2相同.

Tried to avoid using ARG_PREFERENCE_ROOT , but had same crash as on #2 .

根据建议 此处 ,我试图在函数中返回this getCallbackFragment,但这根本没有帮助.

As suggested here, I tried to return this in function getCallbackFragment, but this didn't help at all.

问题

是否有可能让主设置片段只是让用户导航到其他片段,而没有属于它们的其他任何首选项(在preferences.xml内部)?

如何?

推荐答案

您在1)中尝试过的方法是正确的方法-但您不应为此使用<PreferenceScreen>标记.

What you tried in 1) was the correct approach - but you should not use <PreferenceScreen> tags for this.

您的XML资源应该看起来像这样:

Your XML resource should look like this instead:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <Preference
        app:key="screen_preference" 
        app:summary="Shows another screen of preferences"
        app:title="Screen preference"
        app:fragment="com.example.user.myapplication.MainActivity$PrefsFragment2"/>

</PreferenceScreen>

此外,如果您使用的Preference版本早于androidx.preference:preference:1.1.0-alpha01,则需要实现onPreferenceStartFragment来处理片段事务. (在1.1.0 alpha01中,此方法具有默认实现,但仍建议您使用自己的实现来自定义任何动画/过渡)

Also, if you are using a version of Preference older than androidx.preference:preference:1.1.0-alpha01, you will need to implement onPreferenceStartFragment to handle the fragment transaction. (in 1.1.0 alpha01 this method has a default implementation, but you are still encouraged to use your own implementation to customize any animations / transitions)

这应该类似于:

override fun onPreferenceStartFragment(
        caller: PreferenceFragmentCompat,
        pref: Preference
): Boolean {
    // Instantiate the new Fragment
    val args = pref.extras
    val fragment = supportFragmentManager.fragmentFactory.instantiate(
            classLoader,
            pref.fragment,
            args
    ).apply {
        arguments = args
        setTargetFragment(caller, 0)
    }
    // Replace the existing Fragment with the new Fragment
    supportFragmentManager.beginTransaction()
            .replace(R.id.settings, fragment)
            .addToBackStack(null)
            .commit()
    return true
}

有关更多信息,您可以查看设置指南 和 AndroidX首选项示例

For more information you can check out the Settings guide and the AndroidX Preference Sample

更新后的第一个解决方案的样本,可在此处.

a sample of the first solution, after updating, available here.

这是它的工作方式(此处 可用的示例) :

Here's how it can work (sample available here) :

MainActivity.kt

class MainActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
    override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, pref: Preference): Boolean {
        //Note: this whole function won't be needed when using new version of fragment dependency (1.1.0 and above)
        val fragment = Fragment.instantiate(this, pref.fragment, pref.extras)
        fragment.setTargetFragment(caller, 0)
        supportFragmentManager.beginTransaction().replace(android.R.id.content, fragment).addToBackStack(null).commit()
        return true
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        supportActionBar!!.setDisplayHomeAsUpEnabled(true)
        if (savedInstanceState == null)
            supportFragmentManager.beginTransaction().replace(android.R.id.content, PrefsFragment()).commit()
    }

    class PrefsFragment : PreferenceFragmentCompat() {
        override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
            setPreferencesFromResource(R.xml.preferences, rootKey)
        }
    }

    class PrefsFragment2 : PreferenceFragmentCompat() {
        override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
            setPreferencesFromResource(R.xml.preferences2, null)
        }
    }
}

preferences.xml

  <PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">

    <Preference
      app:fragment="com.example.user.myapplication.MainActivity$PrefsFragment2" app:key="screen_preference" app:summary="Shows another screen of preferences"
      app:title="Screen preference"/>

  </PreferenceScreen>

preferences2.xml

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" android:title="Demo">

  <PreferenceCategory android:title="Category">
    <CheckBoxPreference
      android:key="next_screen_checkbox_preference" android:summary="AAAA" android:title="Toggle preference"/>
  </PreferenceCategory>

</PreferenceScreen>

渐变依赖项:

implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.preference:preference:1.0.0'

这篇关于如何使用新的Android-X API从当前的PreferenceFragment中打开一个新的PreferenceFragment?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆