2015-09-09 1 views
15

Мой внутренний экран предпочтений PreferenceFragmentCompat не показывает или, кажется, игнорирует события прослушивания.Внутренний экран предпочтений не открывается с 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> 

И, наконец, создать свой preferences.xml файл как

<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" /> 

Тестирование выше код я не могу открыть/попасть в экран предпочтений. Я что-то упускаю? Почему это не работает?

+0

Опубликовать свою деятельность. – Aryan

+0

Добавил активность, но заметьте, что это не имеет никакого значения, если я добавляю активность в xml или использую FragmentManager и заменяю. Такое же поведение происходит, и если фрагмент предпочтения является частью ViewPager. – madlymad

+2

Если я правильно понял, вы должны обрабатывать вложенные 'PreferenceScreen' сами. Например, если вы добавите это в свой «PreferenceFragmentCompat», он будет работать: '@Override public void onNavigateToScreen (PreferenceScreen preferenceScreen) {setPreferenceScreen (preferenceScreen);}', хотя это, очевидно, не добавит новый экран на кнопку «Назад». Я предполагаю, что они хотят, чтобы мы создавали Intents или обменивали Fragments с помощью этого метода или 'OnPreferenceStartFragmentCallback'. – squirrel

ответ

28

Проведя много часов с попытками, поискать и, к счастью, с некоторой помощью от создателей библиотеки поддержки. Мне удалось заставить его работать.

Шаг 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 (домашнего действия), но это никогда не работает сама по себе ;-)

Я»также создал демо-приложение оборачивать весь этот код вы можете найти его на github.

+0

Спасибо за минимальный работоспособный код. Я расширил вашу работу, добавив обратную стрелку. При входе на экран внутренних предпочтений я стараюсь изменить внешний вид панели действий. Но, я не знаю правильного пути, чтобы восстановить обратную панель действий, когда выходите из внутреннего экрана предпочтений. Мой текущий метод работает, но выглядит немного хаки. https://github.com/yccheok/PreferenceApp/commits/master Пожалуйста, не стесняйтесь предоставлять некоторые данные. Спасибо :) –

+0

@CheokYanCheng Я проверил код. Единственное, что нужно, чтобы избежать хакерских (если это так) onBackPressed, - это реализовать заголовок в onResume фрагмента. Я не уверен, что это прямо или вам нужно использовать его вместе с методом onUserVisible. – madlymad

+0

Спасибо, только переопределив onViewCreated() и покрасив фон представления на белый, помог мне избавиться от черного фона. – AndaluZ

4

Я сделал это несколько иначе, я запускаю новое действие для каждого экрана. Это, кажется, требует меньше хаков: нет необходимости возиться с заменой фрагментов и цветов фона. Вы также получаете анимацию изменения активности в качестве бонуса!

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> 
0

основе @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 библиотеки для чего-то, что работает безупречно вне коробки в стандартном андроида.

0

Решение состоит в том, чтобы запустить другой фрагмент того же класса, но с другим корневым ключом. Никаких действий.

@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(R.id.container, applicationPreferencesFragment) 
      .addToBackStack(null) 
      .commit(); 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^