Как добавить панель действий из библиотеки поддержки в PreferenceActivity?

совместимость панели действий была добавлена в библиотеку поддержки, версия 18. Теперь он имеет ActionBarActivity класс для создания действий с панелью действий на старых версиях Android.

есть ли способ добавить панель действий из библиотеки поддержки в PreferenceActivity?

ранее я использовал ActionBarSherlock и SherlockPreferenceActivity.

8 ответов


EDIT: в appcompat-v7 22.1.0 Google добавил абстрактный класс AppCompatDelegate в качестве делегата, который вы можете использовать для расширения поддержки AppCompat на любую деятельность.

используйте его следующим образом:

...
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatDelegate;
import android.support.v7.widget.Toolbar;
...

public class SettingsActivity extends PreferenceActivity {

    private AppCompatDelegate mDelegate;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        getDelegate().installViewFactory();
        getDelegate().onCreate(savedInstanceState);
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        getDelegate().onPostCreate(savedInstanceState);
    }

    public ActionBar getSupportActionBar() {
        return getDelegate().getSupportActionBar();
    }

    public void setSupportActionBar(@Nullable Toolbar toolbar) {
        getDelegate().setSupportActionBar(toolbar);
    }

    @Override
    public MenuInflater getMenuInflater() {
        return getDelegate().getMenuInflater();
    }

    @Override
    public void setContentView(@LayoutRes int layoutResID) {
        getDelegate().setContentView(layoutResID);
    }

    @Override
    public void setContentView(View view) {
        getDelegate().setContentView(view);
    }

    @Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        getDelegate().setContentView(view, params);
    }

    @Override
    public void addContentView(View view, ViewGroup.LayoutParams params) {
        getDelegate().addContentView(view, params);
    }

    @Override
    protected void onPostResume() {
        super.onPostResume();
        getDelegate().onPostResume();
    }

    @Override
    protected void onTitleChanged(CharSequence title, int color) {
        super.onTitleChanged(title, color);
        getDelegate().setTitle(title);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        getDelegate().onConfigurationChanged(newConfig);
    }

    @Override
    protected void onStop() {
        super.onStop();
        getDelegate().onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        getDelegate().onDestroy();
    }

    public void invalidateOptionsMenu() {
        getDelegate().invalidateOptionsMenu();
    }

    private AppCompatDelegate getDelegate() {
        if (mDelegate == null) {
            mDelegate = AppCompatDelegate.create(this, null);
        }
        return mDelegate;
    }
}

нет больше взлома. Код взят из AppCompatPreferenceActivity.java.


в настоящее время нет способа достичь с помощью AppCompat. Я открыл ошибку внутри.


мне удалось создать обходной путь, аналогичный тому, что использует Google Play Store. ссылка на оригинальный ответ

пожалуйста, найдите репозиторий GitHub:здесь


очень похоже на ваш собственный код, но добавлен xml, чтобы разрешить набор заголовка:

продолжает использовать 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 notes 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


совместимости приложений 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 />s однако, я нашел решение!! - После долгих проб и ошибок!

добавьте к вашему 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:

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

не забывая добавить добавить библиотеку поддержки дизайна в качестве зависимости в :

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 на основе фрагмента support-v4:

https://github.com/kolavar/android-support-v4-preferencefragment

Edit: я только что протестировал его и отлично работает!


интеграция PreferenceActivity с ABC невозможно, по крайней мере для меня. Я попробовал две возможности, которые смог найти, но ни одна не сработала:

Вариант 1:

ActionBarPreferenceActivity выходит PreferenceActivity. Когда вы делаете это, вы ограничиваетесь ActionBarActivityDelegate.createDelegate(ActionBarActivity activity). Также вам нужно реализовать ActionBar.Callbacks которая не работает

Вариант 2:

ActionBarPreferenceActivity выходит ActionBarActivity. Этот подход требует переписывания совершенно нового PreferenceActivity, PreferenceManager и может быть PreferenceFragment что значит нужно доступ к скрытым классам, таким как com.android.internal.util.XmlUtils Решение этого может прийти только от разработчиков Google, реализующих ActionBarWrapper это можно добавить к любой деятельности.

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

однако, мне удалось его реализовать здесь.


История Вопроса:

ОП хочет знать, как мы можем положить MenuItems в ActionBar of PreferenceActivity для pre-Honeycomb, потому что библиотека поддержки Android имеет ошибку, которая не позволяет этому произойти.

Мое Решение:

я нашел гораздо более чистый способ, чем уже предлагалось, для достижения цели (и нашел его в Android Docs):

android:parentActivityName

имя класса логического родителя этот деятельность. Имя должно совпадать с именем класса дано атрибут android:name соответствующего элемента.

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

для поддержки уровней API 4-16 вы также можете объявить родительскую активность с элементом, который указывает значение для "андроид.поддержка.PARENT_ACTIVITY". Например:

<activity
    android:name="com.example.app.ChildActivity"
    android:label="@string/title_child_activity"
    android:parentActivityName="com.example.myfirstapp.MainActivity" >
    <!-- Parent activity meta-data to support API level 4+ -->
    <meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value="com.example.app.MainActivity" />
</activity>

теперь сделайте то, что вы обычно делаете в своем onOptionsItemSelected(). Поскольку он является частью Android Docs, он не имеет побочных эффектов.

удачи в кодировании. :)

обновление:

это решение больше не работает, если вы нацелены на леденец. Если вы используете AppCompat, этой ответ, что вы должны искать.


я смог получить android.app.Actionbar С помощью getActionBar(). Сначала он вернул значение null... затем я подошел к манифесту и сменил тему на:--5-->

android:theme="@style/Theme.AppCompat"

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

это будет хорошо для меня, потому что приложение, над которым я работаю, для ICS/4.0+.


теперь официальный ответ на эту проблему был выпущен. Это поддержка предпочтений v7/v14 библиотека.

посмотреть как использовать библиотеку поддержки предпочтений v7/v14? для обсуждения того, как его использовать.