androidpreference-v7

How to move back from Preferences subscreen to main screen in PreferenceFragmentCompat?


I am trying to implement a Settings screen using PreferenceFragmentCompat. My preference xml has a preference subscreen like this:

preferences.xml

    <CheckBoxPreference
        android:defaultValue="false"
        android:key="@string/pref_sound_key"
        android:summary="@string/pref_sound_summary"
        android:title="@string/pref_sound_title" />

    <PreferenceScreen android:title="Inner Screen">
        <CheckBoxPreference
            android:defaultValue="true"
            android:key="@string/key_1"
            android:title="@string/title_1" />

        <CheckBoxPreference
            android:defaultValue="true"
            android:key="@string/key_1"
            android:title="@string/title_1" />

        <CheckBoxPreference
            android:defaultValue="true"
            android:key="@string/key_2"
            android:title="@string/title_2" />

        <CheckBoxPreference
            android:defaultValue="true"
            android:key="@string/key_3"
            android:title="@string/title_3" />
    </PreferenceScreen>

</PreferenceScreen>

Preference Main Screen

Now, in the app, the subscreen does not open until I implement PreferenceFragmentCompat.OnPreferenceStartScreenCallback interface in parent activity, as specified in PreferenceFragmentCompat doc.

MainActivity.java

public boolean onPreferenceStartScreen(PreferenceFragmentCompat preferenceFragmentCompat,
 PreferenceScreen preferenceScreen) {    
    preferenceFragmentCompat.setPreferenceScreen(preferenceScreen);
    return true;
}

Here's where the problem arises. On implementing the interface, the subscreen opens, but then there is no way I can find to move back to first screen.

Preference Subscreen

Pressing back key closes the app.

Is there any way I can put a back arrow on app bar so that pressing it will bring the main screen back?


Solution

  • By using setPreferenceScreen you are setting the root preference screen to the sub preference screen which is preventing you from having a hierarchy of preference screens to navigate back through.

    I suggest that you treat each PreferenceScreen as a Fragment and add a new Fragment when you navigate into a sub screen.

    @Override
    public boolean onPreferenceStartScreen(PreferenceFragmentCompat preferenceFragmentCompat,
                                           PreferenceScreen preferenceScreen) {
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        MyPreferenceFragment fragment = new MyPreferenceFragment();
        Bundle args = new Bundle();
        args.putString(PreferenceFragmentCompat.ARG_PREFERENCE_ROOT, preferenceScreen.getKey());
        fragment.setArguments(args);
        ft.add(R.id.fragment_container, fragment, preferenceScreen.getKey());
        ft.addToBackStack(preferenceScreen.getKey());
        ft.commit();
        return true;
    }
    

    MyPreferenceFragment

    public class MyPreferenceFragment extends AppPreferenceFragment {
    
       public static final String FRAGMENT_TAG = "my_preference_fragment";
    
       public MyPreferenceFragment() {
       }
    
       @Override
       public void onCreatePreferences(Bundle bundle, String rootKey) {
           setPreferencesFromResource(R.xml.preferences, rootKey);
       }
    }
    

    AppPreferenceFragment

    public abstract class AppPreferenceFragment extends PreferenceFragmentCompat {
    
    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
    
        // Set the default white background in the view so as to avoid transparency
          view.setBackgroundColor(
                  ContextCompat.getColor(getContext(), R.color.background_material_light));
    
      }
    }
    

    That way when you press the back button each Fragment will be popped from the stack.

    For more information see this GitHub project