首选项屏幕自定义布局仅适用于第二次单击
Preference Screen Custom Layout only works with second click
我有一个偏好屏幕使用 'custom layout':
android:layout="@layout/currencycodes"
这个问题是在第一次尝试时无法调出布局。
正如您从下面的动画 gif 中看到的那样,我必须撤退并再次尝试第二次布局才能出现。为什么会这样?
preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:key="application_preferences">
<PreferenceCategory>
<PreferenceScreen
android:key="url_settings"
android:title="@string/url_settings"
android:summary="@string/summary_url_settings">
</PreferenceScreen>
<PreferenceScreen
android:key="currency_codes"
android:title="@string/left_handed"
android:summary="@string/summary_left_handed">
<Preference
android:key="currency_exchanges"
android:layout="@layout/currencycodes"/>
</PreferenceScreen>
<EditTextPreference
android:key="url_exchange_rate"
android:title="@string/url_exchange_rate_settings"
android:summary="@string/summary_url_exchange_rate"
android:enabled = "false"/>
</PreferenceCategory>
</PreferenceScreen>
以下是使用的自定义布局。它包含一个 GridView。
currencycodes.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"
tools:context=".MainActivity">
<GridView
android:layout_width="328dp"
android:layout_height="479dp"
android:layout_marginTop="16dp"
app:layout_constraintTop_toTopOf="parent" android:layout_marginStart="16dp"
app:layout_constraintLeft_toLeftOf="parent" android:layout_marginEnd="16dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="16dp"
android:id="@+id/grdExchanges" android:scrollbars="horizontal|vertical"
android:smoothScrollbar="true" tools:textAlignment="center"
android:verticalScrollbarPosition="defaultPosition"/>
</android.support.constraint.ConstraintLayout>
尝试将您的 if
语句从
更改为
(!mFragMngr.popBackStackImmediate(fragName, 0)
&& mFragMngr.findFragmentByTag(fragName) == null)
至
(mFragMngr.findFragmentByTag(fragName) == null)
首先您需要了解 PreferenceScreen 的工作原理??
来自 [Android 文档][1]:
When it appears inside another preference hierarchy, it is shown and
serves as the gateway to another screen of preferences (either by
showing another screen of preferences as a Dialog or via a
startActivity(android.content.Intent) from the getIntent()). The
children of this PreferenceScreen are NOT shown in the screen that
this PreferenceScreen is shown in. Instead, a separate screen will be
shown when this preference is clicked.
简单来说,
首选项框架处理显示首选项层次结构中的这些其他屏幕。
此 PreferenceScreen 标记用作屏幕中断(类似于文字处理中的分页符)。与其他首选项类型一样,我们在此处分配一个键,以便它能够保存和恢复其实例状态。
在您的情况下,实际发生的是“application_preferences”将用作层次结构的根并提供给 PreferenceActivity.The 第一个屏幕将显示首选项“Url_Setting”和“货币代码”。 “货币代码”是“second_preferencescreen”,单击时将显示另一个首选项屏幕,即“Currency Exchange”(因为它偏好作为“second_preferencescreen”标签的子项,即 Currency Codes)。
所以,这就是为什么它在第一次点击时没有显示....但在第二次点击时希望你得到
首选项屏幕的工作原理...
如果您还有任何疑问...让我知道...
https://developer.android.com/reference/android/preference/PreferenceScreen.html
我想出了一个解决方法。我注意到在 LayoutInflater.java 中扩充布局时,静态哈希图用于收集视图对象:
private static final HashMap<String, Constructor<? extends View>> sConstructorMap
实际情况是,第一次点击调用了 LayoutInflater,但第一次点击仅在静态哈希图中添加了 gridview 视图。您会看到,第一次单击时,命令 sConstructorMap.get(name)
、returns 仅 null:
public final View createView(String name, String prefix, AttributeSet attrs)
throws ClassNotFoundException, InflateException {
Constructor<? extends View> constructor = sConstructorMap.get(name);
Class<? extends View> clazz = null;
try {
if (constructor == null) {
在 LayoutInflater 中,变量 mPrivateFactory 实际上是您的 Main Activity。在那里我的 gridview 将在 mPrivateFactory.onCreateView() 中初始化。但是,第一次单击时,mPrivateFactory.onCreateView() returns null 因为静态哈希图还没有 gridview 的视图....还。它在命令行的下方,onCreateView(parent, name, attrs);
最后添加的地方:
if (view == null && mPrivateFactory != null) {
view = mPrivateFactory.onCreateView(parent, name, context, attrs);
}
if (view == null) {
final Object lastContext = mConstructorArgs[0];
mConstructorArgs[0] = context;
try {
if (-1 == name.indexOf('.')) {
view = onCreateView(parent, name, attrs); <-- ADD TO STATIC HASHMAP
} else {
view = createView(name, null, attrs);
}
} finally {
mConstructorArgs[0] = lastContext;
}
}
因此,在我想出一个更优雅的解决方案之前,我只是在第一次单击该特定首选项时调用方法 onCreateView(parent)
两次。第一次调用将 gridview 添加到静态 hashmap,第二次调用然后(再次)实例化布局视图,但是这次在我自己的 Activity 自己的 onCreateView 方法 mPrivateFactory.onCreateView()
中初始化 gridview:
protected View onCreateView(ViewGroup parent) {
View layout = super.onCreateView(parent);
if(firstCall){
firstCall = false;
layout = super.onCreateView(parent);
}
return layout;
}
可能遇到了几乎相同的问题。在我的 detail/subPreferences 片段中,我只是将首选项引用放入 onCreateView 方法中:
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
setPreferencesFromResource(R.xml.root_preferences, FRAGMENT_TAG);
super.onViewCreated(view, savedInstanceState);
}
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
//setPreferencesFromResource(R.xml.root_preferences, FRAGMENT_TAG);
Log.d(TAG, "onCreatePreferences of the sub screen " + rootKey);
}
我有一个偏好屏幕使用 'custom layout':
android:layout="@layout/currencycodes"
这个问题是在第一次尝试时无法调出布局。 正如您从下面的动画 gif 中看到的那样,我必须撤退并再次尝试第二次布局才能出现。为什么会这样?
preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:key="application_preferences">
<PreferenceCategory>
<PreferenceScreen
android:key="url_settings"
android:title="@string/url_settings"
android:summary="@string/summary_url_settings">
</PreferenceScreen>
<PreferenceScreen
android:key="currency_codes"
android:title="@string/left_handed"
android:summary="@string/summary_left_handed">
<Preference
android:key="currency_exchanges"
android:layout="@layout/currencycodes"/>
</PreferenceScreen>
<EditTextPreference
android:key="url_exchange_rate"
android:title="@string/url_exchange_rate_settings"
android:summary="@string/summary_url_exchange_rate"
android:enabled = "false"/>
</PreferenceCategory>
</PreferenceScreen>
以下是使用的自定义布局。它包含一个 GridView。
currencycodes.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"
tools:context=".MainActivity">
<GridView
android:layout_width="328dp"
android:layout_height="479dp"
android:layout_marginTop="16dp"
app:layout_constraintTop_toTopOf="parent" android:layout_marginStart="16dp"
app:layout_constraintLeft_toLeftOf="parent" android:layout_marginEnd="16dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="16dp"
android:id="@+id/grdExchanges" android:scrollbars="horizontal|vertical"
android:smoothScrollbar="true" tools:textAlignment="center"
android:verticalScrollbarPosition="defaultPosition"/>
</android.support.constraint.ConstraintLayout>
尝试将您的 if
语句从
(!mFragMngr.popBackStackImmediate(fragName, 0)
&& mFragMngr.findFragmentByTag(fragName) == null)
至
(mFragMngr.findFragmentByTag(fragName) == null)
首先您需要了解 PreferenceScreen 的工作原理??
来自 [Android 文档][1]:
When it appears inside another preference hierarchy, it is shown and serves as the gateway to another screen of preferences (either by showing another screen of preferences as a Dialog or via a startActivity(android.content.Intent) from the getIntent()). The children of this PreferenceScreen are NOT shown in the screen that this PreferenceScreen is shown in. Instead, a separate screen will be shown when this preference is clicked.
简单来说,
首选项框架处理显示首选项层次结构中的这些其他屏幕。 此 PreferenceScreen 标记用作屏幕中断(类似于文字处理中的分页符)。与其他首选项类型一样,我们在此处分配一个键,以便它能够保存和恢复其实例状态。
在您的情况下,实际发生的是“application_preferences”将用作层次结构的根并提供给 PreferenceActivity.The 第一个屏幕将显示首选项“Url_Setting”和“货币代码”。 “货币代码”是“second_preferencescreen”,单击时将显示另一个首选项屏幕,即“Currency Exchange”(因为它偏好作为“second_preferencescreen”标签的子项,即 Currency Codes)。
所以,这就是为什么它在第一次点击时没有显示....但在第二次点击时希望你得到 首选项屏幕的工作原理...
如果您还有任何疑问...让我知道... https://developer.android.com/reference/android/preference/PreferenceScreen.html
我想出了一个解决方法。我注意到在 LayoutInflater.java 中扩充布局时,静态哈希图用于收集视图对象:
private static final HashMap<String, Constructor<? extends View>> sConstructorMap
实际情况是,第一次点击调用了 LayoutInflater,但第一次点击仅在静态哈希图中添加了 gridview 视图。您会看到,第一次单击时,命令 sConstructorMap.get(name)
、returns 仅 null:
public final View createView(String name, String prefix, AttributeSet attrs)
throws ClassNotFoundException, InflateException {
Constructor<? extends View> constructor = sConstructorMap.get(name);
Class<? extends View> clazz = null;
try {
if (constructor == null) {
在 LayoutInflater 中,变量 mPrivateFactory 实际上是您的 Main Activity。在那里我的 gridview 将在 mPrivateFactory.onCreateView() 中初始化。但是,第一次单击时,mPrivateFactory.onCreateView() returns null 因为静态哈希图还没有 gridview 的视图....还。它在命令行的下方,onCreateView(parent, name, attrs);
最后添加的地方:
if (view == null && mPrivateFactory != null) {
view = mPrivateFactory.onCreateView(parent, name, context, attrs);
}
if (view == null) {
final Object lastContext = mConstructorArgs[0];
mConstructorArgs[0] = context;
try {
if (-1 == name.indexOf('.')) {
view = onCreateView(parent, name, attrs); <-- ADD TO STATIC HASHMAP
} else {
view = createView(name, null, attrs);
}
} finally {
mConstructorArgs[0] = lastContext;
}
}
因此,在我想出一个更优雅的解决方案之前,我只是在第一次单击该特定首选项时调用方法 onCreateView(parent)
两次。第一次调用将 gridview 添加到静态 hashmap,第二次调用然后(再次)实例化布局视图,但是这次在我自己的 Activity 自己的 onCreateView 方法 mPrivateFactory.onCreateView()
中初始化 gridview:
protected View onCreateView(ViewGroup parent) {
View layout = super.onCreateView(parent);
if(firstCall){
firstCall = false;
layout = super.onCreateView(parent);
}
return layout;
}
可能遇到了几乎相同的问题。在我的 detail/subPreferences 片段中,我只是将首选项引用放入 onCreateView 方法中:
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
setPreferencesFromResource(R.xml.root_preferences, FRAGMENT_TAG);
super.onViewCreated(view, savedInstanceState);
}
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
//setPreferencesFromResource(R.xml.root_preferences, FRAGMENT_TAG);
Log.d(TAG, "onCreatePreferences of the sub screen " + rootKey);
}