我正在尝试学习在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"
希望您能帮助我找到我犯错的地方。
答案 0 :(得分: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不支持它,并且我们会得到编译错误。
感谢所有试图帮助我的人
答案 1 :(得分:0)
看起来您提供的字符串只是发送给您的父级活动的消息。您的家长活动负责实例化正确的Fragment
,并执行仪式来呈现它。
platform docs似乎表示这样:
当用户点击带有关联片段的首选项时,将调用接口方法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