PreferenceFragmentCompat 自定义布局
PreferenceFragmentCompat custom layout
我的 PreferenceFragmentCompat 需要自定义布局。在 PreferenceFragmentCompat 的文档中,您似乎可以在 onCreateView() 中膨胀和 return 视图。
但是 NPE 结果:-
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.setAdapter(android.support.v7.widget.RecyclerView$Adapter)' on a null object reference
at android.support.v7.preference.PreferenceFragmentCompat.bindPreferences(PreferenceFragmentCompat.java:511)
at android.support.v7.preference.PreferenceFragmentCompat.onActivityCreated(PreferenceFragmentCompat.java:316)
at com.cls.example.MyPrefFrag.onActivityCreated(MyPrefFrag.java:42)
在查看 PreferenceFragmentCompat:onCreateView 的源代码后,我发现了以下代码:-
RecyclerView listView = this.onCreateRecyclerView(themedInflater, listContainer, savedInstanceState);
if(listView == null) {
throw new RuntimeException("Could not create RecyclerView");
} else {
this.mList = listView; //problem
...
return view;
}
因此,如果您覆盖 onCreateView() 和 return 自定义布局,则不会调用 onCreateRecyclerView() 并且不会设置 RecyclerView 私有字段 mList。所以 setAdapter() 上的 NPE 结果。
我是否应该假设自定义布局对于 PreferenceFragmentCompat 不可行?
您可以在主题中指定自定义布局。
例如:
styles.xml
<style name="YourTheme" parent="Theme.AppCompat">
<!-- ... -->
<item name="preferenceTheme">@style/YourTheme.PreferenceThemeOverlay</item>
</style>
<style name="YourTheme.PreferenceThemeOverlay" parent="@style/PreferenceThemeOverlay">
<item name="android:layout">@layout/fragment_your_preferences</item>
</style>
fragment_your_preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/custom_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<!-- Required ViewGroup for PreferenceFragmentCompat -->
<FrameLayout
android:id="@android:id/list_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</FrameLayout>
</LinearLayout>
然后在片段 class 的 onViewCreated()
中,您可以开始使用视图:
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
Toolbar toolbar = (Toolbar)view.findViewById(R.id.custom_toolbar);
if (toolbar != null)
{
getMainActivity().setSupportActionBar(toolbar);
}
}
我遇到了同样的问题,但是我的要求有点不同,我只需要在设置列表上方显示一个布局,所以我这样做了
<NestedScrollView>
<ConstrainLayout>
<CustomView>
<SettingsFragmentHolder/>
</ConstraintLayout>
</NestedScrollView>
然后在代码中我只是这样做
FragmentManager.beginTransaction().replace(holder, PreferencesFragment()).commit()
需要注意的一件事是,preferences fragment 有自己的滚动视图或列表,这将导致 NestedScrollView 滚动到 PreferencesFragment 布局的开头,以修复将其添加到 PreferencesFragment 的父布局,在这种情况是 ConstraintLayout
android:descendantFocusability="beforeDescendants"
android:focusableInTouchMode="true"
这将停止默认的滚动行为
我的 PreferenceFragmentCompat 需要自定义布局。在 PreferenceFragmentCompat 的文档中,您似乎可以在 onCreateView() 中膨胀和 return 视图。
但是 NPE 结果:-
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.setAdapter(android.support.v7.widget.RecyclerView$Adapter)' on a null object reference
at android.support.v7.preference.PreferenceFragmentCompat.bindPreferences(PreferenceFragmentCompat.java:511)
at android.support.v7.preference.PreferenceFragmentCompat.onActivityCreated(PreferenceFragmentCompat.java:316)
at com.cls.example.MyPrefFrag.onActivityCreated(MyPrefFrag.java:42)
在查看 PreferenceFragmentCompat:onCreateView 的源代码后,我发现了以下代码:-
RecyclerView listView = this.onCreateRecyclerView(themedInflater, listContainer, savedInstanceState);
if(listView == null) {
throw new RuntimeException("Could not create RecyclerView");
} else {
this.mList = listView; //problem
...
return view;
}
因此,如果您覆盖 onCreateView() 和 return 自定义布局,则不会调用 onCreateRecyclerView() 并且不会设置 RecyclerView 私有字段 mList。所以 setAdapter() 上的 NPE 结果。
我是否应该假设自定义布局对于 PreferenceFragmentCompat 不可行?
您可以在主题中指定自定义布局。
例如:
styles.xml
<style name="YourTheme" parent="Theme.AppCompat">
<!-- ... -->
<item name="preferenceTheme">@style/YourTheme.PreferenceThemeOverlay</item>
</style>
<style name="YourTheme.PreferenceThemeOverlay" parent="@style/PreferenceThemeOverlay">
<item name="android:layout">@layout/fragment_your_preferences</item>
</style>
fragment_your_preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/custom_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<!-- Required ViewGroup for PreferenceFragmentCompat -->
<FrameLayout
android:id="@android:id/list_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</FrameLayout>
</LinearLayout>
然后在片段 class 的 onViewCreated()
中,您可以开始使用视图:
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
Toolbar toolbar = (Toolbar)view.findViewById(R.id.custom_toolbar);
if (toolbar != null)
{
getMainActivity().setSupportActionBar(toolbar);
}
}
我遇到了同样的问题,但是我的要求有点不同,我只需要在设置列表上方显示一个布局,所以我这样做了
<NestedScrollView>
<ConstrainLayout>
<CustomView>
<SettingsFragmentHolder/>
</ConstraintLayout>
</NestedScrollView>
然后在代码中我只是这样做
FragmentManager.beginTransaction().replace(holder, PreferencesFragment()).commit()
需要注意的一件事是,preferences fragment 有自己的滚动视图或列表,这将导致 NestedScrollView 滚动到 PreferencesFragment 布局的开头,以修复将其添加到 PreferencesFragment 的父布局,在这种情况是 ConstraintLayout
android:descendantFocusability="beforeDescendants"
android:focusableInTouchMode="true"
这将停止默认的滚动行为