Создание экрана предпочтений с помощью панели инструментов поддержка (v21
У меня возникли проблемы с использованием новой панели инструментов Material Design в библиотеке поддержки на экране настроек.
У меня есть настройки.XML-файл, как показано ниже:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="@string/AddingItems"
android:key="pref_key_storage_settings">
<ListPreference
android:key="pref_key_new_items"
android:title="@string/LocationOfNewItems"
android:summary="@string/LocationOfNewItemsSummary"
android:entries="@array/new_items_entry"
android:entryValues="@array/new_item_entry_value"
android:defaultValue="1"/>
</PreferenceCategory>
</PreferenceScreen>
строки определяются в другом месте.
13 ответов:
пожалуйста, найдите репозиторий GitHub:здесь
немного опоздал на вечеринку, но это мое решение, которое я использую как обойти продолжает использовать
PreferenceActivity
:
settings_toolbar.xml :
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/toolbar" app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="?attr/actionBarSize" app:navigationContentDescription="@string/abc_action_bar_up_description" android:background="?attr/colorPrimary" app:navigationIcon="?attr/homeAsUpIndicator" app:title="@string/action_settings" />
SettingsActivity.java :
public class SettingsActivity extends PreferenceActivity { @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent(); Toolbar bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false); root.addView(bar, 0); // insert at top bar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); } }
Result :
обновление (совместимость с пряниками):
согласно комментариям, пряник Устройства возвращают исключение NullPointerException в этой строке:
LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();
исправления:
SettingsActivity.java :
public class SettingsActivity extends PreferenceActivity { @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); Toolbar bar; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { LinearLayout root = (LinearLayout) findViewById(android.R.id.list).getParent().getParent().getParent(); bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false); root.addView(bar, 0); // insert at top } else { ViewGroup root = (ViewGroup) findViewById(android.R.id.content); ListView content = (ListView) root.getChildAt(0); root.removeAllViews(); bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false); int height; TypedValue tv = new TypedValue(); if (getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) { height = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics()); }else{ height = bar.getHeight(); } content.setPadding(0, height, 0, 0); root.addView(content); root.addView(bar); } bar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); } }
любые проблемы с вышеизложенным дайте мне знать!
ОБНОВЛЕНИЕ 2: ТОНИРОВКА ОБХОДНОЙ ПУТЬ
как указано во многих заметках dev
PreferenceActivity
не поддерживает тонировку элементов, однако, используя несколько внутренних классов, вы можете добиться этого. То есть до тех пор, пока эти классы не будут удалены. (Работает с помощью appCompat поддержка-В7 в21.0.3).добавить следующий импорт:
import android.support.v7.internal.widget.TintCheckBox; import android.support.v7.internal.widget.TintCheckedTextView; import android.support.v7.internal.widget.TintEditText; import android.support.v7.internal.widget.TintRadioButton; import android.support.v7.internal.widget.TintSpinner;
затем переопределить
onCreateView
способ:@Override public View onCreateView(String name, Context context, AttributeSet attrs) { // Allow super to try and create a view first final View result = super.onCreateView(name, context, attrs); if (result != null) { return result; } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { // If we're running pre-L, we need to 'inject' our tint aware Views in place of the // standard framework versions switch (name) { case "EditText": return new TintEditText(this, attrs); case "Spinner": return new TintSpinner(this, attrs); case "CheckBox": return new TintCheckBox(this, attrs); case "RadioButton": return new TintRadioButton(this, attrs); case "CheckedTextView": return new TintCheckedTextView(this, attrs); } } return null; }
Result:
AppCompat 22.1
AppCompat 22.1 представил новые тонированные элементы, что означает, что больше нет необходимости использовать внутренние классы для достижения того же эффекта, что и последнее обновление. Вместо этого следуйте этому (все еще переопределяя
onCreateView
):@Override public View onCreateView(String name, Context context, AttributeSet attrs) { // Allow super to try and create a view first final View result = super.onCreateView(name, context, attrs); if (result != null) { return result; } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { // If we're running pre-L, we need to 'inject' our tint aware Views in place of the // standard framework versions switch (name) { case "EditText": return new AppCompatEditText(this, attrs); case "Spinner": return new AppCompatSpinner(this, attrs); case "CheckBox": return new AppCompatCheckBox(this, attrs); case "RadioButton": return new AppCompatRadioButton(this, attrs); case "CheckedTextView": return new AppCompatCheckedTextView(this, attrs); } } return null; }
ВЛОЖЕННЫЕ ЭКРАНЫ ПРЕДПОЧТЕНИЙ
многие люди испытывают проблемы с включением панели инструментов во вложенный
<PreferenceScreen />
тем не менее, я нашел решение!! - После долгих проб и ошибок!добавьте к вашему
SettingsActivity
:@SuppressWarnings("deprecation") @Override public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { super.onPreferenceTreeClick(preferenceScreen, preference); // If the user has clicked on a preference screen, set up the screen if (preference instanceof PreferenceScreen) { setUpNestedScreen((PreferenceScreen) preference); } return false; } public void setUpNestedScreen(PreferenceScreen preferenceScreen) { final Dialog dialog = preferenceScreen.getDialog(); Toolbar bar; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { LinearLayout root = (LinearLayout) dialog.findViewById(android.R.id.list).getParent(); bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false); root.addView(bar, 0); // insert at top } else { ViewGroup root = (ViewGroup) dialog.findViewById(android.R.id.content); ListView content = (ListView) root.getChildAt(0); root.removeAllViews(); bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false); int height; TypedValue tv = new TypedValue(); if (getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) { height = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics()); }else{ height = bar.getHeight(); } content.setPadding(0, height, 0, 0); root.addView(content); root.addView(bar); } bar.setTitle(preferenceScreen.getTitle()); bar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dialog.dismiss(); } }); }
причина в том, что
PreferenceScreen
это такая боль, потому что они основаны как диалог обертки, поэтому нам нужно захватить макет диалога, чтобы добавить панель инструментов к нему.
Тень Панели Инструментов
по дизайну импортируя
Toolbar
не допускает возвышения и затенения в устройствах pre-v21, поэтому, если вы хотите иметь возвышение на своемToolbar
вы должны обернуть его вAppBarLayout
:
settings_toolbar.xml
:<android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v7.widget.Toolbar .../> </android.support.design.widget.AppBarLayout>
не забывая добавить добавить библиотеку поддержки дизайна в качестве зависимости в
build.gradle
file:compile 'com.android.support:support-v4:22.2.0' compile 'com.android.support:appcompat-v7:22.2.0' compile 'com.android.support:design:22.2.0'
Android 6.0
у меня есть исследовал сообщенную перекрывающуюся проблему, и я не могу воспроизвести проблему.
полный код в использовании, как указано выше, производит следующее:
если я чего-то не хватает, пожалуйста, дайте мне знать через этот РЕПО и я буду расследовать.
можно использовать
PreferenceFragment
, как альтернативаPreferenceActivity
. Итак, вот обертываниеActivity
пример:public class MyPreferenceActivity extends ActionBarActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.pref_with_actionbar); android.support.v7.widget.Toolbar toolbar = (android.support.v7.widget.Toolbar) findViewById(uk.japplications.jcommon.R.id.toolbar); setSupportActionBar(toolbar); getFragmentManager().beginTransaction().replace(R.id.content_frame, new MyPreferenceFragment()).commit(); } }
и вот файл макета (pref_with_actionbar):
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_height="@dimen/action_bar_height" android:layout_width="match_parent" android:minHeight="?attr/actionBarSize" android:background="?attr/colorPrimary" app:theme="@style/ToolbarTheme.Base" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/> <FrameLayout android:id="@+id/content_frame" android:layout_below="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" /> </RelativeLayout>
и наконец
PreferenceFragment
:public static class MyPreferenceFragment extends PreferenceFragment{ @Override public void onCreate(final Bundle savedInstanceState){ super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.settings); } }
Я надеюсь, что это поможет кому-то.
совершенно новое обновление.
С некоторыми экспериментами я, кажется, нашел рабочее решение AppCompat 22.1+ для вложенных экранов предпочтений.
во-первых, как уже упоминалось во многих ответах (включая один здесь), вам нужно будет использовать новый
AppCompatDelegate
. Любой используйтеAppCompatPreferenceActivity.java
файл из поддержки демонстрационный (https://android.googlesource.com/platform/development/+/58bf5b99e6132332afb8b44b4c8cedf5756ad464/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatPreferenceActivity.java) и просто расширить от него, или скопировать соответствующие функции в свой собственныйPreferenceActivity
. Я покажу первый подход здесь:public class SettingsActivity extends AppCompatPreferenceActivity { @Override public void onBuildHeaders(List<Header> target) { loadHeadersFromResource(R.xml.settings, target); setContentView(R.layout.settings_page); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); ActionBar bar = getSupportActionBar(); bar.setHomeButtonEnabled(true); bar.setDisplayHomeAsUpEnabled(true); bar.setDisplayShowTitleEnabled(true); bar.setHomeAsUpIndicator(R.drawable.abc_ic_ab_back_mtrl_am_alpha); bar.setTitle(...); } @Override protected boolean isValidFragment(String fragmentName) { return SettingsFragment.class.getName().equals(fragmentName); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: onBackPressed(); break; } return super.onOptionsItemSelected(item); } }
сопроводительный макет довольно простой и обычный (
layout/settings_page.xml
):<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.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:elevation="4dp" android:theme="@style/..."/> <ListView android:id="@id/android:list" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
сами предпочтения определяются как обычный (
xml/settings.xml
):<preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> <header android:fragment="com.example.SettingsFragment" android:summary="@string/..." android:title="@string/..."> <extra android:name="page" android:value="page1"/> </header> <header android:fragment="com.example.SettingsFragment" android:summary="@string/..." android:title="@string/..."> <extra android:name="page" android:value="page2"/> </header> ... </preference-headers>
никакой реальной разницы в решениях в сети до этого момента. На самом деле, вы можете использовать это, даже если у вас нет вложенных экранов, нет заголовков, только один экран.
мы используем общие
PreferenceFragment
для всех более глубоких страниц, дифференцированных поextra
параметры в заголовках. Каждая страница будет иметь отдельный XML с общимPreferenceScreen
внутри (xml/settings_page1.xml
и соавт.). Фрагмент использует тот же макет, что и действие, включая панель инструментов.public class SettingsFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getActivity().setTheme(R.style...); if (getArguments() != null) { String page = getArguments().getString("page"); if (page != null) switch (page) { case "page1": addPreferencesFromResource(R.xml.settings_page1); break; case "page2": addPreferencesFromResource(R.xml.settings_page2); break; ... } } } @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View layout = inflater.inflate(R.layout.settings_page, container, false); if (layout != null) { AppCompatPreferenceActivity activity = (AppCompatPreferenceActivity) getActivity(); Toolbar toolbar = (Toolbar) layout.findViewById(R.id.toolbar); activity.setSupportActionBar(toolbar); ActionBar bar = activity.getSupportActionBar(); bar.setHomeButtonEnabled(true); bar.setDisplayHomeAsUpEnabled(true); bar.setDisplayShowTitleEnabled(true); bar.setHomeAsUpIndicator(R.drawable.abc_ic_ab_back_mtrl_am_alpha); bar.setTitle(getPreferenceScreen().getTitle()); } return layout; } @Override public void onResume() { super.onResume(); if (getView() != null) { View frame = (View) getView().getParent(); if (frame != null) frame.setPadding(0, 0, 0, 0); } } }
наконец, краткое резюме того, как это на самом деле работает. Новый
AppCompatDelegate
позволяет нам использовать любые действия с функциями AppCompat, а не только те, которые простираются от действий на самом деле в AppCompat. Это означает, что мы можем превратить старый добрыйPreferenceActivity
в новый и добавить панели инструментов, как обычно. С этого момента мы можем придерживаться старых решений, касающихся экранов предпочтений и заголовков, без каких-либо отклонений от существующей документации. Есть только один важный момент: не используйтеonCreate()
в работе, потому что это приведет к ошибкам. ИспользуйтеonBuildHeaders()
для всех операций, таких как добавление панели инструментов.единственное реальное различие, и это то, что делает его работать с вложенными экранами является то, что вы можете использовать тот же подход с фрагментами. Вы можете использовать их
onCreateView()
таким же образом, раздувая свой собственный макет вместо системного, добавляя панель инструментов так же, как и в действии.
Если вы хотите использовать PreferenceHeaders вы можете использовать следующий подход:
import android.support.v7.widget.Toolbar; public class MyPreferenceActivity extends PreferenceActivity Toolbar mToolbar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ViewGroup root = (ViewGroup) findViewById(android.R.id.content); LinearLayout content = (LinearLayout) root.getChildAt(0); LinearLayout toolbarContainer = (LinearLayout) View.inflate(this, R.layout.activity_settings, null); root.removeAllViews(); toolbarContainer.addView(content); root.addView(toolbarContainer); mToolbar = (Toolbar) toolbarContainer.findViewById(R.id.toolbar); } @Override public void onBuildHeaders(List<Header> target) { loadHeadersFromResource(R.xml.pref_headers, target); } // Other methods }
layout / activity_settings.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_height="?attr/actionBarSize" android:layout_width="match_parent" android:minHeight="?attr/actionBarSize" android:background="?attr/colorPrimary" app:theme="@style/AppTheme" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/> </LinearLayout>
вы можете использовать любой макет, который вы предпочитаете здесь, просто убедитесь, что вы настроить его в Java-код, а также.
и, наконец, ваш файл с заголовками (xml / pref_headers.xml)
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> <header android:fragment="com.example.FirstFragment" android:title="@string/pref_header_first" /> <header android:fragment="com.example.SecondFragment" android:title="@string/pref_header_second" /> </preference-headers>
с выпуском библиотеки поддержки Android 22.1.0 и нового AppCompatDelegate, здесь вы можете найти хороший пример реализации PreferenceActivity с материальной поддержкой с обратной совместимостью.
обновление Он работает на вложенных экранах тоже.
хотя приведенные выше ответы кажутся сложными, если вы хотите быстро исправить решение для использования панели инструментов с поддержкой API 7 и все время расширяя
PreferenceActivity
, Я получил помощь от этого проекта ниже.https://github.com/AndroidDeveloperLB/ActionBarPreferenceActivity
activity_settings.xml
<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" > <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/app_theme_light" app:popupTheme="@style/Theme.AppCompat.Light" app:theme="@style/Theme.AppCompat" /> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:padding="@dimen/padding_medium" > <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout>
SettingsActivity.java
public class SettingsActivity extends PreferenceActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_settings); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); addPreferencesFromResource(R.xml.preferences); toolbar.setClickable(true); toolbar.setNavigationIcon(getResIdFromAttribute(this, R.attr.homeAsUpIndicator)); toolbar.setTitle(R.string.menu_settings); toolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); } private static int getResIdFromAttribute(final Activity activity, final int attr) { if (attr == 0) { return 0; } final TypedValue typedvalueattr = new TypedValue(); activity.getTheme().resolveAttribute(attr, typedvalueattr, true); return typedvalueattr.resourceId; } }
Я тоже искал решение для добавления v7 панель инструментов поддержка (API 25) в AppCompatPreferenceActivity (который автоматически создается AndroidStudio при добавлении SettingsActivity). Прочитав несколько решений и попробовав каждое из них, я изо всех сил пытался получить сгенерированные примеры PreferenceFragment для отображения с помощью панели инструментов.
модифицированное решение, которое вроде как работало, было от "Габор".
одно из предостережений, с которым я столкнулся, было "onBuildHeaders" только один раз. Если вы поворачиваете устройство (например, телефон) вбок, представление воссоздается, и PreferenceActivity снова остается без панели инструментов, однако PreferenceFragments сохранит их.
Я попытался использовать "onPostCreate" для вызова "setContentView", в то время как это работало, чтобы воссоздать панель инструментов, когда ориентация изменилась, PreferenceFragments затем будет отображаться пустым.
что я придумал с рычагами почти каждый совет и ответ я мог прочитать об этом предмете. Я надеюсь, что другие тоже найдут это полезным.
начнем с Java
первый in (сгенерированный)AppCompatPreferenceActivity.java Я изменил 'setSupportActionBar' вот так:
public void setSupportActionBar(@Nullable Toolbar toolbar) { getDelegate().setSupportActionBar(toolbar); ActionBar bar = getDelegate().getSupportActionBar(); bar.setHomeButtonEnabled(true); bar.setDisplayHomeAsUpEnabled(true); }
второй Я создал новый класс с именем AppCompatPreferenceFragment.java (это текущее неиспользуемое имя, хотя это не может остаться таким образом!):
abstract class AppCompatPreferenceFragment extends PreferenceFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.activity_settings, container, false); if (view != null) { Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar_settings); ((AppCompatPreferenceActivity) getActivity()).setSupportActionBar(toolbar); } return view; } @Override public void onResume() { super.onResume(); View frame = (View) getView().getParent(); if (frame != null) frame.setPadding(0, 0, 0, 0); } }
это та часть ответа Габора, которая сработала.
последние, чтобы получить последовательность, нужно внести некоторые изменения в SettingsActivity.java:
public class SettingsActivity extends AppCompatPreferenceActivity { boolean mAttachedFragment; @Override protected void onCreate(Bundle savedInstanceState) { mAttachedFragment = false; super.onCreate(savedInstanceState); } @Override @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void onBuildHeaders(List<Header> target) { loadHeadersFromResource(R.xml.pref_headers, target); } @Override public void onAttachFragment(Fragment fragment) { mAttachedFragment = true; super.onAttachFragment(fragment); } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); //if we didn't attach a fragment, go ahead and apply the layout if (!mAttachedFragment) { setContentView(R.layout.activity_settings); setSupportActionBar((Toolbar)findViewById(R.id.toolbar_settings)); } } /** * This fragment shows general preferences only. It is used when the * activity is showing a two-pane settings UI. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static class GeneralPreferenceFragment extends AppCompatPreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.pref_general); setHasOptionsMenu(true); bindPreferenceSummaryToValue(findPreference("example_text")); bindPreferenceSummaryToValue(findPreference("example_list")); } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == android.R.id.home) { startActivity(new Intent(getActivity(), SettingsActivity.class)); return true; } return super.onOptionsItemSelected(item); } } }
некоторый код был оставлен вне деятельности для краткости. Ключевыми компонентами здесь являются' onAttachedFragment','onPostCreate', и что 'GeneralPreferenceFragment' теперь расширяет обычай - AppCompatPreferenceFragment вместо PreferenceFragment.
Резюме Код: если фрагмент присутствует, фрагмент вводит новый макет и вызывает измененную функцию setSupportActionBar. Если фрагмент отсутствует, SettingsActivity вводит новый макет на 'onPostCreate'
теперь XML (очень просто):
activity_settings.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <include layout="@layout/app_bar_settings" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
app_bar_settings.xml:
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/content_frame" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context=".SettingsActivity"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.NoActionBar.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar_settings" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.NoActionBar.PopupOverlay" /> </android.support.design.widget.AppBarLayout> <include layout="@layout/content_settings" /> </android.support.design.widget.CoordinatorLayout>
content_settings.xml:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/content" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context=".SettingsActivity" tools:showIn="@layout/app_bar_settings"> <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="wrap_content" /> </RelativeLayout>
Конечный Результат:
у меня есть новое (возможно, более аккуратное) решение, которое использует
AppCompatPreferenceActivity
из образцов поддержки v7. С этим кодом в руке я создал свой собственный макет, который включает в себя панель инструментов:<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context="edu.adelphi.Adelphi.ui.activity.MainActivity"> <android.support.design.widget.AppBarLayout android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay"/> </android.support.design.widget.AppBarLayout> <FrameLayout android:id="@+id/content" android:layout_width="match_parent" android:layout_height="match_parent"/> </android.support.design.widget.CoordinatorLayout>
тогда, на мой
AppCompatPreferenceActivity
, Я изменилsetContentView
чтобы создать мой новый макет, и поместите предоставленный макет внутри моегоFrameLayout
:@Override public void setContentView(@LayoutRes int layoutResID) { View view = getLayoutInflater().inflate(R.layout.toolbar, null); FrameLayout content = (FrameLayout) view.findViewById(R.id.content); getLayoutInflater().inflate(layoutResID, content, true); setContentView(view); }
тогда я просто расширяю
AppCompatPreferenceActivity
, что позволяет мне назватьsetSupportActionBar((Toolbar) findViewById(R.id.toolbar))
, а также надувать пункты меню на панели инструментов. Сохраняя преимуществаPreferenceActivity
.
давайте держать его простым и чистым здесь, не нарушая никаких встроенных макетов
import android.support.design.widget.AppBarLayout; import android.support.v4.app.NavUtils; import android.support.v7.widget.Toolbar; private void setupActionBar() { Toolbar toolbar = new Toolbar(this); AppBarLayout appBarLayout = new AppBarLayout(this); appBarLayout.addView(toolbar); final ViewGroup root = (ViewGroup) findViewById(android.R.id.content); final ViewGroup window = (ViewGroup) root.getChildAt(0); window.addView(appBarLayout, 0); setSupportActionBar(toolbar); // Show the Up button in the action bar. getSupportActionBar().setDisplayHomeAsUpEnabled(true); toolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onBackPressed(); } }); }
я нашел это простое решение, работая над этим. Сначала нам нужно создать макет для активности.
activity_settings.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.my.package"> <android.support.v7.widget.Toolbar android:id="@+id/tool_bar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:elevation="@dimen/appbar_elevation" app:navigationIcon="?attr/homeAsUpIndicator" app:navigationContentDescription="@string/abc_action_bar_up_description" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> <ListView android:id="@android:id/list" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/tool_bar" /> </RelativeLayout>
убедитесь, что вы добавили представление списка с
android:id="@android:id/list"
, в противном случае он будет бросатьNullPointerException
следующий шаг-добавить (переопределить)
onCreate
метод в настройках активности
Settings.java
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_settings); Toolbar toolbar = (Toolbar) findViewById(R.id.tool_bar); toolbar.setTitle(R.string.action_settings); toolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); }
убедитесь, что вы импортировали
android.suppoer.v7.widget.Toolbar
. Это должно работать в значительной степени на всех API выше 16 (Jelly Bean и вверх)
Я хотел бы продолжить отмеченное решение Джеймса Кросса, так как после этого возникает проблема закрытия только активного вложенного экрана (PreferenceFragment), чтобы не закрывать SettingsActivity.
На самом деле он работает на всех вложенных экранах (поэтому я не понимаю решение Gábor, которое я пробовал без успеха, Ну он работает до определенного момента, но это беспорядок из нескольких панелей инструментов), потому что когда пользователь нажимает на экран суб предпочтений, только фрагмент изменен (см.
<FrameLayout android:id="@+id/content_frame" .../>
) Не панель инструментов, которая всегда остается активной и видимой,но пользовательское поведение должно быть реализовано, чтобы закрыть каждый фрагмент соответственно.в основном классе
SettingsActivity
что расширяетActionBarActivity
следующие методы должны быть реализованы. Обратите внимание, что частнаяsetupActionBar()
вызывается изonCreate()
private void setupActionBar() { Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar); //Toolbar will now take on default Action Bar characteristics setSupportActionBar(toolbar); getSupportActionBar().setHomeButtonEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: onBackPressed(); return true; } return super.onOptionsItemSelected(item); } @Override public void onBackPressed() { if (getFragmentManager().getBackStackEntryCount() > 0) { getFragmentManager().popBackStackImmediate(); //If the last fragment was removed then reset the title of main // fragment (if so the previous popBackStack made entries = 0). if (getFragmentManager().getBackStackEntryCount() == 0) { getSupportActionBar() .setTitle(R.string.action_settings_title); } } else { super.onBackPressed(); } }
на title из выбранного вложенного экрана вы должны получить ссылку на панель инструментов и установить соответствующий заголовок с
toolbar.setTitle(R.string.pref_title_general);
(например).здесь не нужно для реализации
getSupportActionBar()
во всех PreferenceFragment, так как только вид фрагмента изменяется при каждой фиксации, а не на панели инструментов;здесь не нужно чтобы создать поддельный класс ToolbarPreference для добавления в каждом предпочтении.xml (см. ответ Габора).
вот библиотека, которую я сделал, которая основана на коде AOSP, который добавляет тонировку как к настройкам, так и к диалоговым окнам, добавляет панель действий и поддерживает все версии из API 7 :
https://github.com/AndroidDeveloperLB/MaterialPreferenceLibrary
Ну, это все еще проблема для меня сегодня (18 ноября 2015). Я пробовал все решения из этой темы, но есть две основные вещи, которые я не мог решить:
- вложенные экраны предпочтений появились без панели инструментов
- предпочтения не имели материального взгляда на pre-Lollipop устройствах
поэтому я в конечном итоге создал библиотеку с более сложным решением. В принципе, мне пришлось внутренне применить стили к предпочтениям, если мы используем pre-Lollipop device и я также обрабатывали вложенные экраны, используя пользовательский фрагмент (восстановление всей вложенной иерархии с использованием PreferenceScreen ключ).
библиотека эта:https://github.com/ferrannp/material-preferences
и если вы заинтересованы в исходном коде (слишком долго, чтобы разместить его здесь), это по сути ядро это: https://github.com/ferrannp/material-preferences/blob/master/library/src/main/java/com/fnp/materialpreferences/PreferenceFragment.java