and*_*per 8 android android-preferences android-fragments preferencefragment androidx
在以前版本的支持库中,我们可以使用标题来拥有一个设置的主菜单屏幕,每个屏幕都会打开一个新的设置屏幕(片段)。
现在标题消失了(如这里所写)一段时间,我认为在 android-x 上情况变得更糟:
你会注意到这里没有的一件事是首选项标题,你是完全正确的。然而,这并不意味着单个偏好列表需要跨越 10 英寸平板电脑屏幕。相反,您的 Activity 可以实现 OnPreferenceStartFragmentCallback ( link ) 以使用 app:fragment 属性或 OnPreferenceStartScreenCallback ( link ) 处理首选项以处理 PreferenceScreen 首选项。这允许您在一个窗格中构造“标题”样式 PreferenceFragmentCompat 并使用这些回调替换第二个窗格,而无需在两种不同类型的 XML 文件中工作。
问题是,我没有在新的 android-x API 上使用这些。
每个片段都有自己的首选项 XML 树(使用setPreferencesFromResource内onCreatePreferences),但我提出的每个解决方案要么什么都不做,要么崩溃。
以直观的方式来说,这就是我想要实现的目标:
由于有多个子设置屏幕,将所有子设置屏幕的所有首选项都放在主设置屏幕的一个 XML 文件中会非常麻烦。
我唯一成功的是使用 PreferenceScreen 来保存应该显示的子屏幕的首选项。
这是此类事情的工作代码(可在此处获得项目):
首选项.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>
Run Code Online (Sandbox Code Playgroud)
主活动.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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是,正如我所写的,这不是我想要做的。我想要多个扩展 PreferenceFragmentCompat 的类,每个类都有自己的 XML 文件,这些文件将从主文件中打开。
以下是我尝试过(但失败了)的事情:
为 , 设置一个“android:fragment”PreferenceScreen以指向新的片段类,类似于标题。这根本没有做任何事情。
使用普通的 Preference 并为其设置单击侦听器,这将执行原始代码中显示的片段事务。这导致了类似“具有键 screen_preference 的 Preference object is not a PreferenceScreen” 之类的崩溃。
试图避免使用 ARG_PREFERENCE_ROOT ,但与 #2 上的崩溃相同。
正如这里所建议的,我试图返回this函数getCallbackFragment,但这根本没有帮助。
是否可以让主要设置片段只让用户导航到其他片段,而没有任何其他属于它们的首选项(内部preferences.xml)?
如何?
仅供参考,如果您使用导航抽屉+ androidx.appcompat,您可以:
1) 将每个 PreferenceScreen 子项拆分为与preference.xml 文件一样多的文件:即“Pref_general.xml”将是主要首选项,“pref_ServerSettings.xml”包含具有服务器设置的 PreferenceScreen 子项。2)为每个preference.xml创建一个PreferenceFragmentCompat:
“PrefFragment常规”
在您的 PrefFragmentGeneral.xml 文件中,为任何子 xml 添加一个 Preference 而不是像下面这样的 PreferenceScreen:
<Preference
android:key="pref_serverPref"
android:summary="@string/settings_serverPrefSum"
android:title="@string/settings_serverPrefTitle"
/>
Run Code Online (Sandbox Code Playgroud)
“首选片段服务器”
2) 确保覆盖“onCreatePreferences”以从您想要的 XML 文件中设置首选项:
public class PrefFragmentGeneral extends PreferenceFragmentCompat {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.Pref_general, rootKey);
//find your preference(s) using the same key
Preference serverPref=findPreference("pref_serverPref");
if(serverPref!=null){
//Assign the click listener to navigate to the fragment using the navigation controller
serverPref.setOnPreferenceClickListener(preference -> {
NavController navController = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
navController.navigate(R.id.nav_PrefFragmentServer);
return true;
});
}
}
//and the PrefFragmentServer
public class PrefFragmentServer extends PreferenceFragmentCompat {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.pref_ServerSettings,rootKey);
}
}
Run Code Online (Sandbox Code Playgroud)
3)在导航抽屉中注册所有片段:
现在享受吧!
优点:当您返回时,您将返回到“常规”首选项,就像回到 PreferenceActivity 子项一样!并且您不会收到异常告诉您该片段不是 FragmentManager 的一部分。
小智 3
您在 1) 中尝试的方法是正确的方法 - 但您不应该<PreferenceScreen>为此使用标签。
您的 XML 资源应该如下所示:
<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>
Run Code Online (Sandbox Code Playgroud)
另外,如果您使用的 Preference 版本早于androidx.preference:preference:1.1.0-alpha01,则需要实现 onPreferenceStartFragment 来处理片段事务。(在 1.1.0 alpha01 中,此方法有默认实现,但仍然鼓励您使用自己的实现来自定义任何动画/过渡)
这应该看起来像:
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
}
Run Code Online (Sandbox Code Playgroud)
有关更多信息,您可以查看设置指南和AndroidX 首选项示例
编辑:更新后第一个解决方案的示例,可在此处获取。
以下是它的工作原理(此处提供示例):
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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
首选项.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>
Run Code Online (Sandbox Code Playgroud)
偏好2.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>
Run Code Online (Sandbox Code Playgroud)
梯度依赖:
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.preference:preference:1.0.0'
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6841 次 |
| 最近记录: |