Создание экрана предпочтений с помощью панели инструментов поддержка (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 112

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 :

example


обновление (совместимость с пряниками):

согласно комментариям, пряник Устройства возвращают исключение 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:

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

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

полный код в использовании, как указано выше, производит следующее:

enter image description here

если я чего-то не хватает, пожалуйста, дайте мне знать через этот РЕПО и я буду расследовать.

можно использовать 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 с материальной поддержкой с обратной совместимостью.

обновление Он работает на вложенных экранах тоже.

https://android.googlesource.com/platform/development/+/marshmallow-mr3-release/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatPreferenceActivity.java

хотя приведенные выше ответы кажутся сложными, если вы хотите быстро исправить решение для использования панели инструментов с поддержкой 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>

Конечный Результат:

SettingsActivity

GeneralPreferenceFragment

у меня есть новое (возможно, более аккуратное) решение, которое использует 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