Как вернуться с подэкрана настроек на главный экран в PreferenceFragmentCompat?

Я пытаюсь реализовать экран настроек с помощью PreferenceFragmentCompat. В моем предпочтительном xml есть такой подэкран предпочтений:

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>

Главный экран настроек

Теперь в приложении подэкран не открывается, пока я не реализую интерфейс PreferenceFragmentCompat.OnPreferenceStartScreenCallback в родительской активности, как указано в документе PreferenceFragmentCompat.

MainActivity.java

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

Вот где возникает проблема. При реализации интерфейса открывается подэкран, но я не могу найти способ вернуться к первому экрану.

Подэкран настроек

Нажатие кнопки возврата закрывает приложение.

Есть ли способ поместить стрелку назад на панель приложения, чтобы при нажатии на нее возвращался главный экран?


person Arpit Jaiswal    schedule 10.09.2015    source источник


Ответы (2)


Используя setPreferenceScreen, вы устанавливаете корневой экран предпочтений на вспомогательный экран предпочтений, который не позволяет вам иметь иерархию экранов предпочтений для перехода назад.

Я предлагаю вам рассматривать каждый PreferenceScreen как фрагмент и добавлять новый фрагмент при переходе на дополнительный экран.

@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));

  }
}

Таким образом, когда вы нажимаете кнопку «Назад», каждый фрагмент будет извлечен из стека.

Для получения дополнительной информации см. Этот проект GitHub.

person Scott Cooper    schedule 22.09.2015
comment
Можете ли вы добавить к тому, что вы имеете в виду, рассматривая каждый PreferenceScreen, имеющий фрагмент. Должен ли я определить два фрагмента предпочтений: один для основных настроек, а другой - для внутренних? Как мне этого добиться? - person Arpit Jaiswal; 11.10.2015
comment
@ArpitJaiswal Да, вам нужен один фрагмент для каждого PreferenceScreen, но вы можете повторно использовать MyPreferenceFragment, создав новый экземпляр для каждого PreferenceScreen и передав ключ PreferenceScreen. Этот ключ используется в MyPreferenceFragment для расширения XML ваших настроек. Я только что добавил к своему ответу ссылку на GitHub, в которой есть дополнительная информация. - person Scott Cooper; 11.10.2015
comment
Это не обрабатывается с помощью кнопки возврата на главную (стрелка назад на панели действий / инструментов, она просто закрывает все действия с настройками. - person Pete; 12.07.2016
comment
Какая связь между MyPreferenceFragment и AppPreferenceFragment? - person Stealth Rabbi; 29.05.2020
comment
@StealthRabbi PreferenceFragments по умолчанию имеет прозрачный фон, AppPreferenceFragment - это простой базовый класс, который применяет белый фон к каждому фрагменту, который его расширяет. Оглядываясь назад, вероятно, есть более эффективные способы достижения того же результата. - person Scott Cooper; 29.05.2020

Я добавил полный рабочий пример со снимками экрана и фрагментами кода сюда, в этот пост, надеюсь, это будет кому-то полезно.

Он охватывает следующие сценарии: - 1) Главный экран настроек с двумя флажками и заголовком подэкрана. 2) При щелчке по заголовку подэкрана открывается новый подэкран предпочтений. 3) При обратном нажатии элемент управления переходит на главный экран настроек. Так что с задним прессом обращаются правильно.

MainActivity выглядит так (переопределенный метод onPreferenceStartScreen обрабатывает открытие нового подэкрана в новом окне): -

  public class MainActivity extends AppCompatActivity implements PreferenceFragmentCompat.OnPreferenceStartScreenCallback {

    private static final String TAG = MainActivity.class.getName();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        FragmentManager fragmentManager = getSupportFragmentManager();
        Fragment fragment = null;
        if (savedInstanceState == null) {
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            fragment = new AdvancedSettingsFragment().newInstance("Advanced Setting");
            fragmentTransaction.add(R.id.fragment_container, fragment);
            fragmentTransaction.commit();
        }
    }

    @Override
        public boolean onPreferenceStartScreen(PreferenceFragmentCompat preferenceFragmentCompat,
                                           PreferenceScreen preferenceScreen) {
        Log.d(TAG, "callback called to attach the preference sub screen");
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        AdvancedSettingsSubScreenFragment fragment = AdvancedSettingsSubScreenFragment.newInstance("Advanced Settings Subscreen");
        Bundle args = new Bundle();
        //Defining the sub screen as new root for the  subscreen
        args.putString(PreferenceFragmentCompat.ARG_PREFERENCE_ROOT, preferenceScreen.getKey());
        fragment.setArguments(args);
        ft.replace(R.id.fragment_container, fragment, preferenceScreen.getKey());
        ft.addToBackStack(null);
        ft.commit();
        return true;
    }

и, наконец, фрагмент подэкрана setPreferencesFromResource(R.xml.preferences, rootKey); обрабатывает прикрепление субэкрана к корневому ключу.

public class AdvancedSettingsSubScreenFragment extends PreferenceFragmentCompat {
    private static final String TAG = AdvancedSettingsSubScreenFragment.class.getName();
    public static final String PAGE_ID = "page_id";

    public static AdvancedSettingsSubScreenFragment newInstance(String pageId) {
        AdvancedSettingsSubScreenFragment f = new AdvancedSettingsSubScreenFragment();
        Bundle args = new Bundle();
        args.putString(PAGE_ID, pageId);
        f.setArguments(args);
        return (f);
    }

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        // rootKey is the name of preference sub screen key name , here--customPrefKey
        setPreferencesFromResource(R.xml.preferences, rootKey);
        Log.d(TAG, "onCreatePreferences of the sub screen " + rootKey);
    }
}
person Nicks    schedule 20.03.2016
comment
Можно ли избежать единого XML-файла глобальных настроек и использовать его для каждого фрагмента подпараметров? Я спросил об этом здесь: stackoverflow.com/q/52723661/878126 - person android developer; 10.10.2018