Как создать группы заголовков предпочтений в Android PreferenceActivity?

Я использую заголовки предпочтений для создания настроек с помощью функции PreferenceActivity . Я пытаюсь разделить заголовки на категории / группы, как этот (есть категории Wireless & Networks, Device, Personal, …):

В любом случае, даже этот сайт разработчиков Android об этом способе создания активности предпочтений, я не мог найти способ создания такой же активности предпочтений, как у них на изображении. Единственное, что мне удалось сделать, это простой список заголовков предпочтений.

Единственное, что я нашел, это то , но это работает … странно. Так что это не похоже на выбор.

Поэтому мой вопрос: как создать PreferenceActivity с использованием заголовков предпочтений с возможностью разделения заголовков на категории и с возможностью использования мастер-переключателей включения / выключения?

Некоторые из моего кода:

Preference_headers.xml :

 <?xml version="1.0" encoding="utf-8"?> <preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> <header android:fragment="cz.vse.myevents.activity.SettingsActivity$EventsFragment" android:title="@string/settings_events" android:icon="@android:drawable/ic_menu_agenda" /> <header android:fragment="cz.vse.myevents.activity.SettingsActivity$OrganizationsFragment" android:title="@string/settings_subscribed_organizations" android:icon="@android:drawable/ic_menu_view" /> </preference-headers> 

SettingsActivity :

 @Override public void onBuildHeaders(List<Header> target) { super.onBuildHeaders(target); loadHeadersFromResource(R.xml.preference_headers, target); } 

Я не размещаю ресурсы фрагментов, думаю, что это не нужно.

Solutions Collecting From Web of "Как создать группы заголовков предпочтений в Android PreferenceActivity?"

Я думаю, что то, что вы нашли на сайте Xavier Gouchet, – это то, как мы должны это делать. Я посмотрел исходный код в приложении настроек Android, и это то, что извлекло Gouchet. Я адаптировал его для своих целей (оставив выключатель звукового сигнала) и получил заголовок категории с разделительной линией.

Я надеюсь, что Android API для настроек будет расширен для поддержки категорий в ближайшее время. Это не должно быть так сложно.

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

Вот пример макета

 <PreferenceCategory android:title="Heading1"> <Preference android:title="title1" android:summary="summary1" android:key="keyName"/> <Preference android:title="title2" android:summary="summary2" android:key="keyName"/> </PreferenceCategory> <PreferenceCategory android:title="Heading2"> <Preference android:title="title3" android:summary="summary3" android:key="keyName"/> </PreferenceCategory> 

Кажется, лучшим решением является создание трех разных блоков кода – один для pre-Honeycomb, один для post-Honeycomb и один для планшетов.

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

Заголовки предпочтений на post-Honeycomb кажутся бесполезными, поэтому лучше всего использовать типичный PreferenceScreen в PreferenceFragment . PreferenceCategory можно легко сделать группами.

И, наконец, для pre-Honeycomb, устаревший способ без использования PrefrenceFragment – единственный способ.

К сожалению, существует много дубликатов кода, но библиотека UnifiedPreference упомянутая в ответе Leandros, ошибочна – она ​​полностью игнорирует PreferenceFragment поэтому она бесполезна (по крайней мере для меня).

Чтобы уточнить ответ от Т. Фолсом , вот моя реализация:

разреш / макет / preference_header_item.xml

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?android:attr/activatedBackgroundIndicator" android:baselineAligned="false" android:gravity="center_vertical" android:minHeight="48dp" android:paddingRight="?android:attr/scrollbarSize" > <LinearLayout android:layout_width="@dimen/header_icon_width" android:layout_height="wrap_content" android:layout_marginLeft="6dip" android:layout_marginRight="6dip" > <ImageView android:id="@+id/icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> </LinearLayout> <RelativeLayout android:layout_width="0dip" android:layout_height="wrap_content" android:layout_marginBottom="6dip" android:layout_marginLeft="2dip" android:layout_marginRight="6dip" android:layout_marginTop="6dip" android:layout_weight="1" > <TextView android:id="@+android:id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ellipsize="marquee" android:fadingEdge="horizontal" android:singleLine="true" android:textAppearance="?android:attr/textAppearanceMedium" /> <TextView android:id="@+android:id/summary" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@android:id/title" android:ellipsize="end" android:maxLines="2" android:textAppearance="?android:attr/textAppearanceSmall" /> </RelativeLayout> </LinearLayout> 

RES / значения / dimens.xml

 <resources> <dimen name="header_icon_width">28dp</dimen> </resources> 

В вашем классе PreferenceActivity:

  @Override protected void onCreate(Bundle savedInstanceState) { if (savedInstanceState != null) { /* * the headers must be restored before the super call in order * to be ready for the call to setListAdapter() */ if (savedInstanceState.containsKey("headers")) { setHeaders((ArrayList<Header>)savedInstanceState.getSerializable("headers")); } } // as suggest by https://stackoverflow.com/questions/15551673/android-headers-categories-in-preferenceactivity-with-preferencefragment if(onIsMultiPane()) getIntent().putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, PreferencesFragment.class.getName()); super.onCreate(savedInstanceState); ... } @Override protected void onResume() { super.onResume(); // https://stackoverflow.com/questions/15551673/android-headers-categories-in-preferenceactivity-with-preferencefragment // Select the displayed fragment in the headers (when using a tablet) : // This should be done by Android, it is a bug fix if(getHeaders() != null) { final String displayedFragment = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT); if (displayedFragment != null) { for (final Header header : getHeaders()) { if (displayedFragment.equals(header.fragment)) { switchToHeader(header); break; } } } } ... } /** * Populate the activity with the top-level headers. */ @Override public void onBuildHeaders(List<Header> target) { // we have to save the headers as the API call getHeaders() is hidden. setHeaders(target); loadHeadersFromResource(R.xml.settings_headers, target); } private List<Header> headers; private void setHeaders(List<Header> headers) { this.headers = headers; } private List<Header> getHeaders() { return headers; } @Override protected void onSaveInstanceState(Bundle outState) { outState.putSerializable("headers", (ArrayList<PreferenceActivity.Header>)headers); super.onSaveInstanceState(outState); } @Override public void setListAdapter(ListAdapter adapter) { if (adapter == null) { super.setListAdapter(null); } else { super.setListAdapter(new HeaderAdapter(this, getHeaders())); } } private static class HeaderAdapter extends ArrayAdapter<Header> { static final int HEADER_TYPE_CATEGORY = 0; static final int HEADER_TYPE_NORMAL = 1; private static final int HEADER_TYPE_COUNT = HEADER_TYPE_NORMAL + 1; private static class HeaderViewHolder { ImageView icon; TextView title; TextView summary; } private LayoutInflater mInflater; static int getHeaderType(Header header) { if (header.fragment == null && header.intent == null) { return HEADER_TYPE_CATEGORY; } else { return HEADER_TYPE_NORMAL; } } @Override public int getItemViewType(int position) { Header header = getItem(position); return getHeaderType(header); } @Override public boolean areAllItemsEnabled() { return false; // because of categories } @Override public boolean isEnabled(int position) { return getItemViewType(position) != HEADER_TYPE_CATEGORY; } @Override public int getViewTypeCount() { return HEADER_TYPE_COUNT; } @Override public boolean hasStableIds() { return true; } public HeaderAdapter(Context context, List<Header> objects) { super(context, 0, objects); mInflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public View getView(int position, View convertView, ViewGroup parent) { HeaderViewHolder holder; Header header = getItem(position); int headerType = getHeaderType(header); View view = null; if (convertView == null) { holder = new HeaderViewHolder(); switch (headerType) { case HEADER_TYPE_CATEGORY: view = new TextView(getContext(), null, android.R.attr.listSeparatorTextViewStyle); holder.title = (TextView) view; break; case HEADER_TYPE_NORMAL: view = mInflater.inflate(R.layout.preference_header_item, parent, false); holder.icon = (ImageView) view.findViewById(R.id.icon); holder.title = (TextView) view .findViewById(android.R.id.title); holder.summary = (TextView) view .findViewById(android.R.id.summary); break; } view.setTag(holder); } else { view = convertView; holder = (HeaderViewHolder) view.getTag(); } // All view fields must be updated every time, because the view may // be recycled switch (headerType) { case HEADER_TYPE_CATEGORY: holder.title.setText(header.getTitle(getContext() .getResources())); break; case HEADER_TYPE_NORMAL: holder.icon.setImageResource(header.iconRes); holder.title.setText(header.getTitle(getContext() .getResources())); CharSequence summary = header.getSummary(getContext() .getResources()); if (!TextUtils.isEmpty(summary)) { holder.summary.setVisibility(View.VISIBLE); holder.summary.setText(summary); } else { holder.summary.setVisibility(View.GONE); } break; } return view; } } 

Со всем этим кодом на месте создание заголовков просто:

 <preference-headers xmlns:android="http://schemas.android.com/apk/res/android" > <header android:title="atitle" /> </preference-headers> 

Надеюсь, это поможет кому-то. Я знаю, мне потребовалось некоторое время, чтобы нормально работать.

На самом деле это довольно просто. Из того, что я нашел, корневая PreferenceActivity сама по себе не поддерживает добавление в нее заголовков категорий / секций, кажется, что вы можете добавлять только Header s – что не очень интересно.

Итак, что вам сначала нужно сделать, это не делать тяжелую работу в вашей PreferenceActivity и сразу загружать PreferenceFragment :

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTitle("Settings"); // Display the fragment as the main content. getFragmentManager().beginTransaction() .replace(android.R.id.content, new PreferencesFragment()) .commit(); } public static class PreferencesFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.prefs); } } 

Как только вы это сделаете, вы можете теперь выполнять всю работу в вашем PreferenceFragment , и отличная новость заключается в том, что теперь вы можете использовать категории !

Ваш файл R.xml.prefs должен выглядеть примерно так:

 <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > <PreferenceCategory android:summary="Login credentials" android:title="Login credentials" > <EditTextPreference android:key="username" android:summary="Username" android:title="Username" /> <EditTextPreference android:key="password" android:summary="Password" android:title="Password" /> </PreferenceCategory> <PreferenceCategory android:summary="Settings" android:title="Settings" > <CheckBoxPreference android:key="persist" android:summary="Yes/No" android:title="Keep me signed in" /> </PreferenceCategory> </PreferenceScreen> 

Просто создайте PreferenceCategory для каждой новой категории, которую вы хотите добавить.

Реализация AOSP settings_headers.xml:

 <preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> <!-- WIRELESS and NETWORKS --> <header android:title="@string/header_category_wireless_networks" /> <!-- Wifi --> <header android:id="@+id/wifi_settings" android:fragment="com.android.settings.wifi.WifiSettings" android:title="@string/wifi_settings_title" android:icon="@drawable/ic_settings_wireless" /> <!-- Bluetooth --> <header android:id="@+id/bluetooth_settings" android:fragment="com.android.settings.bluetooth.BluetoothSettings" android:title="@string/bluetooth_settings_title" android:icon="@drawable/ic_settings_bluetooth2" /> <!-- Data Usage --> <header android:id="@+id/data_usage_settings" android:fragment="com.android.settings.DataUsageSummary" android:title="@string/data_usage_summary_title" android:icon="@drawable/ic_settings_data_usage" /> <!-- Operator hook --> <header android:fragment="com.android.settings.WirelessSettings" android:id="@+id/operator_settings"> <intent android:action="com.android.settings.OPERATOR_APPLICATION_SETTING" /> </header> <!-- Other wireless and network controls --> <header android:id="@+id/wireless_settings" android:title="@string/radio_controls_title" android:breadCrumbTitle="@string/wireless_networks_settings_title" android:fragment="com.android.settings.WirelessSettings" android:icon="@drawable/empty_icon" /> <!-- Ethernet --> <header android:id="@+id/ethernet_settings" android:title="@string/eth_radio_ctrl_title" android:icon="@drawable/ic_settings_ethernet" android:fragment="com.android.settings.ethernet.EthernetSettings"/> <!-- DEVICE --> <header android:title="@string/header_category_device" /> <!-- Sound --> <header android:id="@+id/sound_settings" android:icon="@drawable/ic_settings_sound" android:fragment="com.android.settings.SoundSettings" android:title="@string/sound_settings" /> <!-- Display --> <header android:id="@+id/display_settings" android:icon="@drawable/ic_settings_display" android:fragment="com.android.settings.DisplaySettings" android:title="@string/display_settings" /> <!-- Storage --> <header android:id="@+id/storage_settings" android:fragment="com.android.settings.deviceinfo.Memory" android:icon="@drawable/ic_settings_storage" android:title="@string/storage_settings" /> <!-- Battery --> <header android:id="@+id/battery_settings" android:fragment="com.android.settings.fuelgauge.PowerUsageSummary" android:icon="@drawable/ic_settings_battery" android:title="@string/power_usage_summary_title" /> <!-- Application Settings --> <header android:fragment="com.android.settings.applications.ManageApplications" android:icon="@drawable/ic_settings_applications" android:title="@string/applications_settings" android:id="@+id/application_settings" /> <!-- TEMPORARY FACTORY STARTER WILL BE REMOVED WITH UPDATED SETTINGS --> <header android:icon="@drawable/ic_settings_applications" android:title="Factory" android:id="@+id/application_settings" > <intent android:action="android.intent.action.MAIN" android:targetPackage="com.jamdeo.tv.sample.factory" android:targetClass="com.jamdeo.tv.sample.factory.TvFactoryMainActivity" /> </header> <!-- Manufacturer hook --> <header android:fragment="com.android.settings.WirelessSettings" android:id="@+id/manufacturer_settings"> <intent android:action="com.android.settings.MANUFACTURER_APPLICATION_SETTING" /> </header> <!-- PERSONAL --> <header android:title="@string/header_category_personal" /> <!-- Data Sync. The settings activity will ensure this is resolved to an activity on the system image, otherwise it will remove this preference. --> <header android:fragment="com.android.settings.accounts.ManageAccountsSettings" android:icon="@drawable/ic_settings_sync" android:title="@string/sync_settings" android:id="@+id/sync_settings" /> <!-- Location --> <header android:fragment="com.android.settings.LocationSettings" android:icon="@drawable/ic_settings_location" android:title="@string/location_settings_title" android:id="@+id/location_settings" /> <!-- Security --> <header android:fragment="com.android.settings.SecuritySettings" android:icon="@drawable/ic_settings_security" android:title="@string/security_settings_title" android:id="@+id/security_settings" /> <!-- Language --> <header android:id="@+id/language_settings" android:fragment="com.android.settings.inputmethod.InputMethodAndLanguageSettings" android:icon="@drawable/ic_settings_language" android:title="@string/language_settings" /> <!-- Backup and reset --> <header android:fragment="com.android.settings.PrivacySettings" android:icon="@drawable/ic_settings_backup" android:title="@string/privacy_settings" android:id="@+id/privacy_settings" /> <!-- SYSTEM --> <header android:title="@string/header_category_system" /> <!-- Dock --> <header android:id="@+id/dock_settings" android:fragment="com.android.settings.DockSettings" android:icon="@drawable/ic_settings_dock" android:title="@string/dock_settings" /> <!-- Date & Time --> <header android:id="@+id/date_time_settings" android:fragment="com.android.settings.DateTimeSettings" android:icon="@drawable/ic_settings_date_time" android:title="@string/date_and_time_settings_title" /> <!-- Accessibility feedback --> <header android:id="@+id/accessibility_settings" android:fragment="com.android.settings.AccessibilitySettings" android:icon="@drawable/ic_settings_accessibility" android:title="@string/accessibility_settings" /> <!-- Development --> <header android:id="@+id/development_settings" android:fragment="com.android.settings.DevelopmentSettings" android:icon="@drawable/ic_settings_development" android:title="@string/development_settings_title" /> <!-- About Device --> <header android:id="@+id/about_settings" android:fragment="com.android.settings.DeviceInfoSettings" android:icon="@drawable/ic_settings_about" android:title="@string/about_settings" /> </preference-headers> 

Просто используйте <header> только с атрибутом android:title .