it-swarm.com.ru

Создание экрана настроек с поддержкой (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>

Строки определены в другом месте.

114
James Cross

Вы можете использовать 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);
    }
}

Я надеюсь, что это помогает кому-то.

105
James Cross

Пожалуйста, найдите репозиторий 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


ОБНОВЛЕНИЕ (Совместимость с пряниками):

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

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

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

enter image description here

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

108
David Passmore

Полностью новое обновление.

Поэкспериментировав, я, кажется, нашел работающее решение AppCompat 22.1+ для вложенных экранов предпочтений.

Во-первых, как упоминалось во многих ответах (включая один здесь), вам нужно будет использовать новое AppCompatDelegate. Либо используйте файл AppCompatPreferenceActivity.Java из демонстрационных файлов поддержки ( https://Android.googlesource.com/platform/development/+/58bf5b99e6132332afb8b44b4c8cedf5756ad464/samples/Support7Demos/src/com/example/Appid.App7 .Addroid. 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() таким же образом, надувая свой собственный макет вместо системного, добавляя панель инструментов так же, как в упражнении.

48
Gábor

Если вы хотите использовать 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>
18
Sven Dubbeld

С выпуском библиотеки поддержки 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

17
MrBrightside

Я тоже искал решение для добавления 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

6
SilverX

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

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

5
Bryan

Давайте будем простыми и чистыми, не нарушая встроенный макет

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();
        }
    });
}
5
Samuel

Я нашел это простое решение, работая над этим. Для начала нам нужно создать макет для настройки активности.

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

Следующим шагом является добавление (Override) 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 и выше)

4
Apurva

Я хотел бы продолжить отмеченное решение Джеймса Кросса, поскольку после этого возникает проблема закрытия только активного вложенного экрана (PreferenceFragment) таким образом, чтобы также не закрывать SettingsActivity.

На самом деле он работает на всех вложенных экранах (так что я не понимаю решение Gábor, которое я безуспешно пробовал, хорошо, что оно работает до определенного момента, но это беспорядок из нескольких панелей инструментов), потому что, когда пользователь щелкает экран дополнительных настроек изменен только фрагмент (см. <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 (см. Ответ Габора).

1
Davideas

Вот библиотека, которую я сделал, которая основана на коде AOSP, который добавляет тонирование как к настройкам, так и к диалогам, добавляет панель действий и поддерживает все версии из API 7:

https://github.com/AndroidDeveloperLB/MaterialPreferenceLibrary

1
android developer

Ну, это все еще проблема для меня сегодня (18 ноября 2015 года). Я перепробовал все решения из этой ветки, но я не смог решить две основные проблемы:

  • Вложенные экраны предпочтений появились без панели инструментов
  • В настройках не было материала, выглядящего на устройствах перед леденцом на палочке

В итоге я создал библиотеку с более сложным решением. По сути, мне пришлось внутренне применять стили к предпочтениям, если мы используем устройство до Lollipop, и я также обрабатывал вложенные экраны с помощью пользовательского фрагмента (восстанавливая всю вложенную иерархию, используя преимущества PreferenceScreen ключ ).

Это библиотека: https://github.com/ferrannp/material-preferences

И если вы заинтересованы в исходном коде (слишком долго, чтобы публиковать его здесь), это в основном его ядро: https://github.com/ferrannp/material-preferences/blob/master/library/ SRC/главная/Java/COM/ФНП/materialpreferences/PreferenceFragment.Java

1
Ferran Negre