I need a custom layout for my PreferenceFragmentCompat. In the docs for PreferenceFragmentCompat it seems that you can possibly inflate and return a view in onCreateView().
However a NPE results:-
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)
After I checked the source of PreferenceFragmentCompat:onCreateView I found the following piece of code :-
RecyclerView listView = this.onCreateRecyclerView(themedInflater, listContainer, savedInstanceState);
if(listView == null) {
throw new RuntimeException("Could not create RecyclerView");
} else {
this.mList = listView; //problem
...
return view;
}
So if you override onCreateView() and return a custom layout the onCreateRecyclerView() is not called plus the RecyclerView private field mList will not be set. So the NPE on setAdapter() results.
Should I assume that having a custom layout is not feasible for PreferenceFragmentCompat ?
You can specify a custom layout in your theme.
For example:
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>
And then in onViewCreated()
of your fragment class you can start using the views:
@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);
}
}
I had the same problem, however my requirements were a bit different, I just needed to show a layout above the settings list, so I did this
<NestedScrollView>
<ConstrainLayout>
<CustomView>
<SettingsFragmentHolder/>
</ConstraintLayout>
</NestedScrollView>
Then later in code I just do this
FragmentManager.beginTransaction().replace(holder, PreferencesFragment()).commit()
One thing to note is that, preferences fragment has its own scrollview or a list, that will cause the NestedScrollView to scroll to the beginning of PreferencesFragment layout, to fix that add this to the parent layout of the PreferencesFragment, in this case it is ConstraintLayout
android:descendantFocusability="beforeDescendants"
android:focusableInTouchMode="true"
That will stop the default scrolling behavior
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With