Создание экрана предпочтений с поддержкой (v21) Панели инструментов
У меня возникла проблема с использованием новой панели инструментов Material Design в библиотеке поддержки на экране настроек.
У меня есть файл settings.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>
Строки определяются в другом месте.
Ответы
Ответ 1
Вы можете использовать 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);
}
}
Я надеюсь, что это поможет кому-то.
Ответ 2
Пожалуйста, найдите GitHub Repo: Здесь
Немного поздно для вечеринки, но это мое решение, которое я использую для продолжения использования 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 :
![example]()
UPDATE (совместимость с пряничными):
В соответствии с комментариями, Gingerbread Devices возвращают NullPointerException в этой строке:
LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();
FIX:
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: ТРЕБОВАНИЯ К РАБОТЕ
Как указано во многих примечаниях разработчика PreferenceActivity
не поддерживает тонирование элементов, однако, используя несколько внутренних классов, вы можете достичь этого. Это до тех пор, пока эти классы не будут удалены. (Работает с использованием поддержки appCompat-v7 v21.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:
![example 2]()
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
:
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
Я исследовал описанную проблему перекрытия, и я не могу воспроизвести проблему.
Полный код, используемый выше, дает следующее:
![введите описание изображения здесь]()
Если мне что-то не хватает, сообщите мне через это репо, и я буду исследовать.
Ответ 3
Полностью новое обновление.
При некоторых экспериментах я, похоже, нашел рабочее решение 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()
таким же образом, раздувая свой собственный макет вместо системного, добавив панель инструментов так же, как и в действие.
Ответ 4
Если вы хотите использовать 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
}
Макет/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>
Ответ 5
С выпуском Android Support Library 22.1.0 и нового AppCompatDelegate здесь вы можете найти хороший пример реализации PreferenceActivity с материальной поддержкой с обратной совместимостью.
Обновление
Он также работает на вложенных экранах.
https://android.googlesource.com/platform/development/+/marshmallow-mr3-release/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatPreferenceActivity.java
Ответ 6
Хотя приведенные выше ответы кажутся сложными, если вы хотите быстро исправить решение для использования панели инструментов с поддержкой 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;
}
}
Ответ 7
Я также искал решение добавить панель инструментов поддержки v7 (API 25) в AppCompatPreferenceActivity (которая автоматически создается AndroidStudio при добавлении параметра SettingsActivity), Прочитав несколько решений и попробовав каждый из них, я изо всех сил пытался отобразить созданные примеры PreferenceFragment с помощью панели инструментов.
Модифицированное решение, от которого работал, было " Gabor".
Один из предостережений, с которыми я столкнулся, был только один раз на "onBuildHeaders". Если вы поворачиваете устройство (например, телефон) сбоку, представление воссоздается, и функция PreferenceActivity остается без панели инструментов, однако PreferenceFragments сохранит их.
Я попытался использовать 'onPostCreate' для вызова 'setContentView', в то время как это сработало, чтобы воссоздать панель инструментов при изменении ориентации, PreferenceFragments затем будет отображаться пустым.
То, что я придумал, использует почти каждый совет и ответ, который я мог бы прочитать по этому вопросу. Я надеюсь, что другие считают это полезным.
Мы начнем с Java
Первый в (сгенерированном) 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>
Конечный результат:
![SettingsActivity]()
![GeneralPreferenceFragment]()
Ответ 8
Пусть это будет простым и чистым, не нарушая встроенный макет
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();
}
});
}
Ответ 9
Я нашел это простое решение, работая над этим.
Сначала нам нужно создать макет для активности настроек.
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 и выше)
Ответ 10
У меня есть новое (возможно, более аккуратное) решение, которое использует 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
.
Ответ 11
Я хотел бы продолжить отмеченное решение Джеймса Кросса, поскольку после этого возникает проблема закрытия только активного вложенного экрана (PreferenceFragment), чтобы не закрывать также SettingsActivity.
На самом деле он работает на всех вложенных экранах (поэтому я не понимаю решение Gábor, которое я пробовал без успеха, хорошо работает до определенного момента, но это путаница нескольких панелей инструментов), потому что когда пользователь нажимает кнопку sub preference screen, только фрагмент изменен (см. <FrameLayout android:id="@+id/content_frame" .../>
), а не панель инструментов, которая всегда остается активной и видимой, но для того, чтобы закрыть каждый фрагмент, должно быть реализовано индивидуальное поведение.
В основном классе SettingsActivity
, который расширяется ActionBarActivity
, должны быть реализованы следующие методы. Обратите внимание, что private 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 для добавления в каждый файл preference.xml(см. ответ Gábor).
Ответ 12
Вот библиотека, которую я создал, на основе кода AOSP, который добавляет оттенок как для предпочтений, так и для диалогов, добавляет панель действий и поддерживает все версии из API 7:
https://github.com/AndroidDeveloperLB/MaterialPreferenceLibrary
Ответ 13
Хорошо, это все еще проблема для меня сегодня (18 ноября 2015 года). Я пробовал все решения из этой темы, но я не мог решить две основные вещи:
- Вложенные экраны предпочтений появились без панели инструментов
- Предпочтения не отображались в материале на устройствах, предшествующих Lollipop.
Итак, я создал библиотеку с более сложным решением. В принципе, мне пришлось внутренне применять стили к предпочтениям, если мы используем устройство pre-Lollipop, а также обработали вложенные экраны с помощью пользовательского фрагмента (восстановление всей вложенной иерархии с использованием ключа PreferenceScreen).
Библиотека - это: https://github.com/ferrannp/material-preferences
И если вас интересует исходный код (слишком длинный, чтобы опубликовать его здесь), это в основном его суть: https://github.com/ferrannp/material-preferences/blob/master/library/src/main/java/com/fnp/materialpreferences/PreferenceFragment.java