如何在首选项标头中使用PreferenceFragmentCompat

问题描述 投票:3回答:2

我正在尝试学习在Xamarin Android应用程序中构建首选项页面的方法。我在PreferenceFragment中找到了很多例子,但它被标记为已弃用,我很难在当前阶段重写它们。

我创建了表示标题的活动。我添加了IntentFilter,因此我可以从设置菜单中的应用列表中访问此活动。它还有内部类,可以将一些首选项组合在一起:

namespace droid.examples.Preferences
{
    [Activity(Label = "Settings activity", Theme = "@style/AppTheme", Name = "droid.examples.Preferences.SettingsActivity")]
    [IntentFilter(new string[] { "android.intent.action.APPLICATION_PREFERENCES" })]
    public class SettingsActivity : PreferenceActivity
    {
        public override void OnBuildHeaders(IList<Header> target)
        {
            base.OnBuildHeaders(target);
            LoadHeadersFromResource(Resource.Xml.preference_headers, target);
        }

        public class SettingsFragment : PreferenceFragmentCompat
        {
            public override void OnCreatePreferences(Bundle savedInstanceState, string rootKey)
            {
                // Load the Preferences from the XML file
                SetPreferencesFromResource(Resource.Xml.app_preferences, rootKey);
            }
        }
    }
}

我的app_preferences.xml,我无法通过从preference_headers.xml中选择“Prefs 1”标头打开:

<?xml version="1.0" encoding="utf-8" ?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
  <PreferenceCategory android:title="Category">
    <CheckBoxPreference
            android:key="checkbox_preference"
            android:title="Developer mode"
            android:summary="Allow user to see detailed messages" />
  </PreferenceCategory>
</PreferenceScreen>

我有preference_headers.xml。当我点击应用程序名称附近的齿轮时它会打开。它看起来像这样:

<?xml version="1.0" encoding="utf-8" ?>
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
  <header android:fragment="droid.examples.Preferences.SettingsActivity.SettingsFragment"
          android:title="Prefs 1"
          android:summary="An example of some preferences." />
</preference-headers>

我的包名:droid.examples

我认为有一个问题与android:fragment属性值有关。建立这个价值的规则是什么?

我想它必须从'包名'开始。它应该在类名和包名之间包含名称空间吗?

$属性值的含义是什么?它用于标记内部类吗?我在下面的几个地方看到了代码:

android:fragment="com.example.android.apis.preference.PreferenceWithHeaders$Prefs1Fragment"

我希望你能帮助我找到我犯错误的地方。

Source code from GitHub

android xamarin xamarin.android
2个回答
1
投票

我花了很多时间来调查这个问题,我想做一个总结。

我们必须在SettingsActivity中覆盖IsValidFragment方法:

protected override bool IsValidFragment(string fragmentName)
{
    return fragmentName == "droid.examples.preferences.SettingsActivity.SettingsFragment";
}

我的SettingsActivity扩展了PreferenceActivity。感谢@Jeremy关于IOnPreferenceStartFragmentCallback实现的建议,我发现基类已经扩展了它。

public abstract class PreferenceActivity ...
{
    ...
    public virtual bool OnPreferenceStartFragment(PreferenceFragment caller, Preference pref);
    ...
}

所以,我可能需要使用PreferenceFragment而不是PreferenceFragmentCompat来使代码保持一致:

public class SettingsFragment : PreferenceFragment
{
    public override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        AddPreferencesFromResource(Resource.Xml.app_preferences_for_header);
    }
}

我们还必须在我们的片段中添加Register属性:

[Register("droid.examples.preferences.SettingsActivity.SettingsFragment")]
public class SettingsFragment : PreferenceFragment
{
}

最后我更新了preference_headers.xml

<?xml version="1.0" encoding="utf-8" ?>
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
  <header android:fragment="droid.examples.preferences.SettingsActivity.SettingsFragment"
          android:title="Prefs 1"
          android:summary="An example of some preferences." />
</preference-headers>

android:fragment属性值可以包含'$'但是'+'不起作用,因为Register不支持它,我们将得到编译错误。

谢谢所有试图帮助我的人


0
投票

看起来您提供的字符串只是要发送到父活动的消息。您的父活动负责实例化正确的Fragment,并执行仪式以呈现它。

platform docs似乎表明如下:

当用户使用关联的片段点击Preference时,将调用接口方法PreferenceFragmentCompat.OnPreferenceStartFragmentCallback.onPreferenceStartFragment()

在撰写本文时,该页面上有一个代码片段,我已经为我自己的项目进行了或多或少的翻译,如下所示:

// This has to go in the activity which hosts the PreferenceFragment
// which owns the Preference that has the `android:fragment` attribute.

using Android.Support.V7.Preferences;
using Android.Support.V4.App;
partial class MyActivity :
   PreferenceFragmentCompat.IOnPreferenceStartFragmentCallback
{

   Fragment GetFragmentForPrefString(string prefFragment)
   {
      // you implement this
   }
   const int fragmentContainerId = Resource.Id.whatever;

   public bool OnPreferenceStartFragment(
      PreferenceFragmentCompat caller, Preference pref)
   {
      string prefString = pref.Fragment;
      var transaction = SupportFragmentManager.BeginTransaction();
      transaction.Replace(fragmentContainerId,
         GetFragmentForPrefString(prefString));

      // you'll probably also want to add it to the back stack,
      // but it's not strictly necessary I guess.

      transaction.Commit();
      return true;
   }
}

他们的示例涉及Java API方法getSupportFragmentManager().getFragmentFactory(),它似乎不是V28 Xamarin支持NuGet包的一部分。但老实说,我不确定为什么这种间接是必要的;我建议你简单地实现类似的东西

switch (prefFragmentName)
{
   case "Fragment 1":
      return new Fragment1();
// etc
© www.soinside.com 2019 - 2024. All rights reserved.