Внутренний PreferenceScreen не открывается с PreferenceFragmentCompat
мой внутренний PreferenceScreen PreferenceFragmentCompat не показывает или, похоже, игнорирует события нажатия.
Я создал MyPreferenceFragment
это extends PreferenceFragmentCompat
public class MyPreferenceFragment extends PreferenceFragmentCompat {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences);
}
}
затем я изменил тему в styles.xml
как
<style name="AppTheme" parent="@style/Theme.AppCompat.Light">
<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
</style>
и, наконец, создать свою как
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference android:title="Check Me"/>
<PreferenceScreen android:title="My Screen"> <!-- This is not opening -->
<EditTextPreference android:title="Edit text" />
</PreferenceScreen>
</PreferenceScreen>
на build.gradle
я добавил Как:
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:preference-v7:23.0.1'
код Активность
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
activity_main.в XML
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment"
android:name="com.mando.preferenceapp.MyPreferenceFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
тестирование вышеуказанного кода я не могу открыть / попасть в экран настроек. Я что-то упускаю? Почему это не работает?
4 ответов
проведя много часов с попытками, поиск и, к счастью, с некоторой помощью от создателей библиотеки поддержки. Мне удалось заставить его работать.
Шаг 1. Activity
public class MyActivity extends AppCompatActivity implements
PreferenceFragmentCompat.OnPreferenceStartScreenCallback {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
// Create the fragment only when the activity is created for the first time.
// ie. not after orientation changes
Fragment fragment = getSupportFragmentManager().findFragmentByTag(MyPreferenceFragment.FRAGMENT_TAG);
if (fragment == null) {
fragment = new MyPreferenceFragment();
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, fragment, MyPreferenceFragment.FRAGMENT_TAG);
ft.commit();
}
}
@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.replace(R.id.fragment_container, fragment, preferenceScreen.getKey());
ft.addToBackStack(preferenceScreen.getKey());
ft.commit();
return true;
}
}
советы.
- не добавлять фрагмент
xml
у вас будут сбои при изменении ориентации. - обрабатывать воссозданные действия / фрагмент добавить в
onCreate
чтобы избежать потери фрагмента, когда внутри экрана предпочтений. - активность хоста фрагмента должна реализовать
PreferenceFragmentCompat.OnPreferenceStartScreenCallback
и воссоздать фрагменты одного и того же экземпляра.
Шаг 2. PreferenceFragment
public class MyPreferenceFragment extends PreferenceFragmentCompat {
public static final String FRAGMENT_TAG = "my_preference_fragment";
public MyPreferenceFragment() {
}
@Override
public void onCreatePreferences(Bundle bundle, String rootKey) {
setPreferencesFromResource(R.xml.preferences, rootKey);
}
}
советы.
- используйте метод
setPreferencesFromResource
и воспользоватьсяrootKey
каждого экрана. Таким образом, ваш код будет использоваться повторно. - имейте в виду, что если у вас есть код типа
findPreference
в вашем фрагменте он должен естьnull
проверяет, как когда вы были на внутренних экранах, это ничего не даст вам.
то, что отсутствует сейчас, - это реализация стрелки назад в actionbar (home action), но это никогда не работает само по себе; -)
Я также создал демо-приложение, обернув весь этот код, который вы можете найти на github.
Я сделал это немного по-другому, я запускаю новое действие для каждого экрана. Это, похоже, требует меньше хаков: нет необходимости возиться с заменой фрагментов и цветов фона. Вы также получаете анимацию изменения активности в качестве бонуса!
public class PreferencesActivity extends AppCompatActivity implements PreferenceFragmentCompat.OnPreferenceStartScreenCallback {
final static private String KEY = "key";
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.preferences);
setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) actionBar.setDisplayHomeAsUpEnabled(true);
if (savedInstanceState != null)
return;
Fragment p = new PreferencesFragment();
String key = getIntent().getStringExtra(KEY);
if (key != null) {
Bundle args = new Bundle();
args.putString(PreferenceFragmentCompat.ARG_PREFERENCE_ROOT, key);
p.setArguments(args);
}
getSupportFragmentManager().beginTransaction()
.add(R.id.preferences, p, null)
.commit();
}
@Override public boolean onPreferenceStartScreen(PreferenceFragmentCompat preferenceFragmentCompat, PreferenceScreen preferenceScreen) {
Intent intent = new Intent(PreferencesActivity.this, PreferencesActivity.class);
intent.putExtra(KEY, preferenceScreen.getKey());
startActivity(intent);
return true;
}
@Override public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
public static class PreferencesFragment extends PreferenceFragmentCompat implements ... {
private static final String FRAGMENT_DIALOG_TAG = "android.support.v7.preference.PreferenceFragment.DIALOG";
private String key;
@Override public void onCreatePreferences(Bundle bundle, String key) {
setPreferencesFromResource(R.xml.preferences, this.key = key);
}
// this only sets the title of the action bar
@Override public void onActivityCreated(Bundle savedInstanceState) {
ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
if (actionBar != null) actionBar.setTitle((key == null) ? "Settings" : findPreference(key).getTitle());
super.onActivityCreated(savedInstanceState);
}
}
}
XML-код:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="0dp"
android:orientation="vertical"
android:padding="0dp"
android:id="@+id/preferences">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary" />
<!-- preference fragment will be inserted here programmatically -->
</LinearLayout>
решение состоит в том, чтобы начать другой фрагмент того же класса, но с другим корневым ключом. Никаких действий активности.
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey){
if(getArguments() != null){
String key = getArguments().getString("rootKey");
setPreferencesFromResource(R.xml.preferences, key);
}else{
setPreferencesFromResource(R.xml.preferences, rootKey);
}
}
@Override
public void onNavigateToScreen(PreferenceScreen preferenceScreen){
ApplicationPreferencesFragment applicationPreferencesFragment = new ApplicationPreferencesFragment();
Bundle args = new Bundle();
args.putString("rootKey", preferenceScreen.getKey());
applicationPreferencesFragment.setArguments(args);
getFragmentManager()
.beginTransaction()
.replace(getId(), applicationPreferencesFragment)
.addToBackStack(null)
.commit();
}
основываясь на решении @ squirrel Intent, я заставил его работать таким образом. Это требует еще меньше взлома.
Активность:
import android.support.v7.app.AppCompatActivity;
public class SettingsActivity extends AppCompatActivity {
public static final String TARGET_SETTING_PAGE = "target";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SettingsFragment settingsFragment = new SettingsFragment();
Intent intent = getIntent();
if (intent != null) {
String rootKey = intent.getStringExtra(TARGET_SETTING_PAGE);
if (rootKey != null) {
settingsFragment.setArguments(Bundler.single(TARGET_SETTING_PAGE, rootKey));
}
}
getFragmentManager().beginTransaction()
.replace(android.R.id.content, settingsFragment)
.commit();
}
}
фрагмент:
import android.support.v14.preference.PreferenceFragment;
public class SettingsFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle arguments = getArguments();
if (arguments != null && arguments.getString(TARGET_SETTING_PAGE) != null) {
setPreferencesFromResource(R.xml.preferences, arguments.getString(TARGET_SETTING_PAGE));
} else {
addPreferencesFromResource(R.xml.preferences);
}
}
@Override
public void onNavigateToScreen(PreferenceScreen preferenceScreen) {
Intent intent = new Intent(getActivity(), SettingsActivity.class)
.putExtra(TARGET_SETTING_PAGE, preferenceScreen.getKey());
startActivity(intent);
super.onNavigateToScreen(preferenceScreen);
}
}
грустно, что вам нужно так много хаков в библиотеках поддержки appcompat для чего-то, что работает безупречно из коробки в стандартном android.