16

Я использую PreferenceFragment в ActionBarActivity из библиотеки поддержки-v7.
В работе у меня есть Toolbar. Все идет хорошо, пока я не открою вложенный PreferenceScreen.
В открытом экране скрыт Toolbar.Панель инструментов скрыта во вложенном PreferenceScreen

Возможно, кто-нибудь знает обходное решение для этой проблемы?

Настройки XML-файл:

<?xml version="1.0" encoding="utf-8"?> 
    <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > 

    <PreferenceCategory android:title="Main category" > 

     <EditTextPreference 
      android:defaultValue="defaultValue" 
      android:key="key_global_setting" 
      android:title="Global title" />   

    </PreferenceCategory> 

    <PreferenceCategory android:title="Nested screens" >   

     <PreferenceScreen 
      android:persistent="false" 
      android:title="@string/settings_facility_title" > 

     <CheckBoxPreference 
      android:defaultValue="false" 
      android:key="nested_screen_1_1" 
      android:title="Nested screen 1.1 check box" /> 

     <CheckBoxPreference 
      android:defaultValue="true" 
      android:key="nested_screen_1_2" 
      android:title="Nested screen 1.2 check box" /> 
     </PreferenceScreen> 

     <PreferenceScreen 
      android:persistent="false" 
      android:title="@string/settings_menu_screen_title" > 

     <CheckBoxPreference 
      android:defaultValue="true" 
      android:key="nested_screen2" 
      android:title="Nested screen 2 check box" /> 
     </PreferenceScreen>   

    </PreferenceCategory>  

</PreferenceScreen> 

раскладка активность:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    xmlns:app="http://schemas.android.com/apk/res-auto"  
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical" 
    tools:context=".SettingsScreen" > 

    <android.support.v7.widget.Toolbar 
     android:id="@+id/toolbar" 
     style="@style/Toolbar" /> 

    <FrameLayout 
     android:id="@+id/contentSettings" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" /> 

</LinearLayout> 
+0

http://stackoverflow.com/a/27455363/2247612 Этот ответ имеет идеальное решение для поддержки библиотеки – harishannam

ответ

26

Я нашел решение самостоятельно. Я использовал небольшую работу вокруг всего этого вложенного PreferenceScreen's. Я просто разделил на разные файлы xml-preference, создал дополнительный Fragment, который расширяет PreferenceFragment, и там я показываю соответствующий экран вложенных настроек.
Возможно, кто-то нашел бы это полезным.

Github sources link.

Некоторые примеры кода ниже:

main_preferences.xml

<?xml version="1.0" encoding="utf-8"?> 
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > 

    <PreferenceCategory android:title="Main category" > 

     <EditTextPreference 
      android:defaultValue="defaultValue" 
      android:key="key_global_setting" 
      android:title="Global title" /> 

    </PreferenceCategory> 

    <PreferenceCategory android:title="Nested screens" > 

     <Preference 
      android:key="NESTED_KEY1" 
      android:persistent="false" 
      android:title="Nested screen #1" /> 

     <Preference 
      android:key="NESTED_KEY2" 
      android:persistent="false" 
      android:title="Nested screen #2" /> 

    </PreferenceCategory> 

</PreferenceScreen> 

nested_screen1_preferences.xml

<?xml version="1.0" encoding="utf-8"?> 
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" 
    android:title="Nested screen #1" > 

    <CheckBoxPreference 
     android:defaultValue="false" 
     android:key="nested_screen_1_1" 
     android:title="Nested screen 1.1 check box" /> 

    <CheckBoxPreference 
     android:defaultValue="true" 
     android:key="nested_screen_1_2" 
     android:title="Nested screen 1.2 check box" /> 
</PreferenceScreen> 

nested_screen2_preferences.xml

<?xml version="1.0" encoding="utf-8"?> 
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" 
    android:title="Nested screen #2"> 

    <CheckBoxPreference 
     android:defaultValue="true" 
     android:key="nested_screen2" 
     android:title="Nested screen 2 check box" /> 
</PreferenceScreen> 

SettingsActivity.java

public class SettingsActivity extends ActionBarActivity implements MyPreferenceFragment.Callback { 

    private static final String TAG_NESTED = "TAG_NESTED"; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_settings); 

     Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 
     if (toolbar != null) { 
      setSupportActionBar(toolbar); 
      getSupportActionBar().setDisplayHomeAsUpEnabled(true); 
     } 

     if (savedInstanceState == null) { 
      getFragmentManager().beginTransaction() 
        .add(R.id.contentSettings, new MyPreferenceFragment()) 
        .commit(); 
     } 
    } 

    @Override 
    public void onBackPressed() { 
     // this if statement is necessary to navigate through nested and main fragments 
     if (getFragmentManager().getBackStackEntryCount() == 0) { 
      super.onBackPressed(); 
     } else { 
      getFragmentManager().popBackStack(); 
     } 
    } 

    @Override 
    public void onNestedPreferenceSelected(int key) { 
     getFragmentManager().beginTransaction().replace(R.id.contentSettings, NestedPreferenceFragment.newInstance(key), TAG_NESTED).addToBackStack(TAG_NESTED).commit(); 
    }  
} 

MyPreferenceFragment.java

// The main preference fragment class 
public class MyPreferenceFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener { 

    private Callback mCallback; 

    private static final String KEY_1 = "NESTED_KEY1"; 
    private static final String KEY_2 = "NESTED_KEY2"; 

    @Override 
    public void onAttach(Activity activity) { 

     super.onAttach(activity); 

     if (activity instanceof Callback) { 
      mCallback = (Callback) activity; 
     } else { 
      throw new IllegalStateException("Owner must implement Callback interface"); 
     } 
    } 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     // Load the preferences from an XML resource 
     addPreferencesFromResource(R.xml.main_preferences); 

     // add listeners for non-default actions 
     Preference preference = findPreference(KEY_1); 
     preference.setOnPreferenceClickListener(this); 

     preference = findPreference(KEY_2); 
     preference.setOnPreferenceClickListener(this); 
    } 

    @Override 
    public boolean onPreferenceClick(Preference preference) { 
     // here you should use the same keys as you used in the xml-file 
     if (preference.getKey().equals(KEY_1)) { 
      mCallback.onNestedPreferenceSelected(NestedPreferenceFragment.NESTED_SCREEN_1_KEY); 
     } 

     if (preference.getKey().equals(KEY_2)) { 
      mCallback.onNestedPreferenceSelected(NestedPreferenceFragment.NESTED_SCREEN_2_KEY); 
     } 

     return false; 
    } 

    public interface Callback { 
     public void onNestedPreferenceSelected(int key); 
    } 
} 

NestedPreferencesFragment.java

public class NestedPreferenceFragment extends PreferenceFragment { 

    public static final int NESTED_SCREEN_1_KEY = 1; 
    public static final int NESTED_SCREEN_2_KEY = 2; 

    private static final String TAG_KEY = "NESTED_KEY"; 

    public static NestedPreferenceFragment newInstance(int key) { 
     NestedPreferenceFragment fragment = new NestedPreferenceFragment(); 
     // supply arguments to bundle. 
     Bundle args = new Bundle(); 
     args.putInt(TAG_KEY, key); 
     fragment.setArguments(args); 
     return fragment; 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 

     super.onCreate(savedInstanceState); 

     checkPreferenceResource(); 
    } 

    private void checkPreferenceResource() { 
     int key = getArguments().getInt(TAG_KEY); 
     // Load the preferences from an XML resource 
     switch (key) { 
      case NESTED_SCREEN_1_KEY: 
       addPreferencesFromResource(R.xml.nested_screen1_preferences); 
       break; 

      case NESTED_SCREEN_2_KEY: 
       addPreferencesFromResource(R.xml.nested_screen2_preferences); 
       break; 

      default: 
       break; 
     } 
    } 

} 
+0

я проверял в этом вопросе в последнее время. Ваше решение приятно, но вы можете использовать только 1 уровень гнездования, не так ли?Любые идеи по расширению этого, чтобы использовать любое количество вложенных экранов предпочтений? Я видел обходное решение сделать панель инструментов в качестве пользовательского предпочтения, которое работает нормально, но мне кажется, что это очень хладнокровно. –

+0

Да, с текущим решением вы можете иметь только 1 уровень гнездования. Во всяком случае, мое решение основано на манипулировании с back-stack фрагмента. Я думаю, что очень возможно добавить дополнительные фрагменты в текущий задний стек и управлять логикой, чтобы создать как можно больше вложенных префов. – yurezcv

+0

Спасибо, брат! Отличный ответ. –

6

вот мое решение, которое вдохновленный оригинальный ответ, но не такой уж и сложный. Может быть, это поможет кому-то ...

layout/settings.xml:

<RelativeLayout 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" > 

     <include 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:layout_alignParentTop="true" 
      layout="@layout/toolbar" /> 

     <LinearLayout 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" 
      android:id="@+id/content" 
      android:layout_below="@+id/toolbar"/> 

    </RelativeLayout> 

Классы:

public class SettingsActivity extends ActionBarActivity { 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
    setContentView(R.layout.settings); 
    super.onCreate(savedInstanceState); 
    initializeSupportActionBar(); 
    getFragmentManager().beginTransaction().replace(R.id.content, new MainFragment()).commit(); 
    } 

    @Override 
    public void onBackPressed() { 
    if(!getFragmentManager().popBackStackImmediate()) super.onBackPressed(); 
    } 
} 

public class MainFragment extends PreferenceFragment { 

    public MainFragment() {} 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    addPreferencesFromResource(R.xml.pref_main); 
    // "nested" is the <Preference android:key="nested" android:persistent="false"/>` 
    findPreference("nested").setOnPreferenceClickListener(new OnPreferenceClickListener() { 
     @Override public boolean onPreferenceClick(Preference preference) { 
     getFragmentManager().beginTransaction().replace(R.id.content, new NestedFragment()).addToBackStack(NestedFragment.class.getSimpleName()).commit(); 
     return true; 
     } 
    }); 
    } 

public class NestedFragment extends PreferenceFragment { 
    ... 
} 

Я испытал это на 4.3 и 5.0.2 и никаких ограничений на уровнях вложенности не применяется

0

В моем решении вам нужно только один AppCompatActivity и один PreferenceFragement, но несколько файлов XML, каждый из которых имеет только один уровень PreferenceScreens.

список XML-файла

  • верхнего уровень PreferenceScreen
  • второго уровня PreferenceScreen 0
  • второго уровня PreferenceScreen 1
  • второго уровня PreferenceScreen 2
  • ...

Этот код предназначен для одного подуровня (для простоты и получения идеи), но вы можете легко расширить его, чтобы иметь произвольные под-уровни PreferenceScreens.

SettingsFragment.java

public class SettingsFragment extends PreferenceFragment 
{ 
    private int xmlId; 

    @Override 
    public void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     xmlId = R.xml.preferences; 
     addPreferencesFromResource(xmlId); 
    } 

    public void changePrefScreen(int xmlId, int titleId) 
    { 
     this.xmlId = xmlId; 
     ((AppCompatActivity)getActivity()).getSupportActionBar().setTitle(getActivity().getResources().getString(titleId)); 
     getPreferenceScreen().removeAll(); 
     addPreferencesFromResource(xmlId); 
    } 

    // will be called by SettingsActivity (Host Activity) 
    public void onUpButton() 
    { 
     if(xmlId == R.xml.preferences) // in top-level 
     { 
      // Switch to MainActivity 
      Intent intent = new Intent(getActivity(), MainActivity.class); 
      startActivity(intent); 
     } 
     else // in sub-level 
     { 
      changePrefScreen(R.xml.preferences, R.string.settings); 
     } 
    } 

    @Override 
    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) 
    { 
     String key = preference.getKey(); 

     // 
     // Top level PreferenceScreen 
     // 
     if(key.equals("top_key_0")) 
     { 
      changePrefScreen(R.xml.download_preference_screen, R.string.download_database); // descend into second level 
     } 

     // ... 

     // 
     // Second level PreferenceScreens 
     // 
     if (key.equals("second_level_key_0")) 
     { 
      // do something... 
     } 

     // ... 
    } 

SettingsActivity.java

public class SettingsActivity extends AppCompatActivity 
{ 
    SettingsFragment settingsFragment; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 

     settingsFragment = new SettingsFragment(); 

     // Display the fragment as the main content. 
     getFragmentManager().beginTransaction() 
       .replace(android.R.id.content, settingsFragment) 
       .commit(); 
    } 

    // 
    // Handle what happens on up button 
    // 
    @Override 
    public boolean onOptionsItemSelected(MenuItem item) 
    { 
     switch (item.getItemId()) 
     { 
      case android.R.id.home: 
       settingsFragment.onUpButton(); 
       return true; 
     } 
     return true; 
    } 

    // ... 
} 

Технически он должен работать на всех Android версии, для которых PreferenceFragment доступно.

0

Поскольку проблема исходит от той части, которую вы до сих пор в том же активности/фрагменте и вложенном прив экран просто диалог, который вы можете сделать следующее:

  • Вы можете установить предпочтение щелчок слушателя
  • Получить вид корня из диалога: (PreferenceScreen)preference).getDialog().getWindow() .getDecorView().getRootView());

  • Рекурсивный поиск, пока не найдете вид заглушки (есть один, к сожалению, я не знаю android.R.id.xxxxx) и установить, что раскладку вам нужно, как название, которое будет выглядеть на панели инструментов (Вы можете надуть панель инструментов):

    private Toolbar toolbar; 
    
        public void findViewStub(ViewGroup viewGroup) { 
        int childCount = viewGroup.getChildCount(); 
        for (int i = 0; i < childCount; i++) { 
         View childView = viewGroup.getChildAt(i); 
         if(childView instanceof ViewStub){ 
          ((ViewStub)childView).setLayoutResource(R.layout.your_title_layout); 
          toolbar = ((ViewStub)childView).inflate(); 
         } 
         if (childView instanceof ViewGroup) { 
          findViewStub((ViewGroup) childView); 
         } 
        } 
    
        } 
    
    toolbar.setNavigationIcon(); 
    toolbar.setNavigationOnClickListener(); 
    toolbar.setTitle(); 
    
  • В макете можно поставить только панель инструментов. И установите задний значок. Регистрируйтесь для клика по нему и со ссылкой на фрагмент, по щелчку вы можете отменить диалог. Вы установили название и т.д.

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