Применить оттенок к виджетам PreferenceActivity с помощью AppCompat v21

Я использую CheckboxPreference в PreferenceActivity и теме AppCompat из библиотеки поддержки v21. Как вы уже знаете, в этой последней библиотеке виджеты, такие как флажки, editTexts, переключатели и т.д., Окрашены второстепенным цветом, определенным в теме. На экране настроек текст имеет правильный цвет, как указано в моей теме, а флажки и текст редактирования - нет. Кажется, что когда экземпляр CheckboxPreference создает виджет, он не применяет к нему мою тему.

Радиокнопки в обычной раскладке, тонированные:

screenshot 1

Флажок от CheckboxPreference, не тонирован:

screenshot 2

Я использую в качестве родительской темы Theme.AppCompat.Light.NoActionBar. Это происходит с каждым подклассом Preference с виджетом, например EditTextPreference, где EditText имеет черную нижнюю линию вместо тонированной линии. Как я могу применить оттенок к виджетам, показанным подклассами Preference?

ОБНОВЛЕНИЕ: тонировка не применяется, потому что PreferenceActivity расширяет активность Activity. В рабочем случае я использую ActionBarActivity из библиотеки поддержки. Теперь вопрос: как получилось?

Ответ 1

До сих пор мое собственное (печальное) решение заключалось в том, чтобы создать с нуля мои собственные ярлыки checkbox, используя цвета, которые должны были быть отмечены в первую очередь.

В styles.xml:

<?xml version="1.0" encoding="utf-8"?>
<style name="AppThemeBase" parent="Theme.AppCompat.Light.NoActionBar">
...
<!-- edit the checkbox appearance -->
<item name="android:listChoiceIndicatorMultiple">@drawable/my_checkbox</item>
...
</style>

вытяжка/my_checkbox.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true" android:drawable="@drawable/checkbox_on" />
    <item android:drawable="@drawable/checkbox_off" />
</selector>

checkbox_on" and checkbox_off` являются чертежами PNG для выбранных и невыбранных состояний, очевидно, для каждой плотности экрана. Если вы не согласны с согласованностью измерений, размер базовой линии (MDPI) для чертежей должен быть 32px полным активом и 18px оптическим квадратом.

Ответ 2

Изменить. С AppCompat 22.1 любая деятельность может быть тематической, используя AppCompatDelegate. Название тонированных классов просмотра также изменилось с v7.internal.widget.TintXYZ на v7.widget.AppCompatXYZ. Ниже приведен ответ для AppCompat 22.0 и старше.


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

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;

public class MyActivity extends PreferenceActivity {
    @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;
    }
}

Это работает, потому что onCreateView вызывается службой LayoutInflater для каждого представления, которое накачивается из ресурса макета, что позволяет активности переопределять, какие классы получают инстанцирован. Убедитесь, что для темы действия задано значение Theme.AppCompat. (или потомков) в манифесте.

См. ActionBarActivity.java и ActionBarActivityDelegateBase.java для исходного кода.

Ответ 3

Я знаю, что эти вопросы старые, но я хотел оставить решение, чтобы преодолеть эту проблему, которую вы испытали. Прежде всего, я хотел бы сказать, что PreferenceActivity является реликтом предшествующих сотовых времен, поэтому не ожидайте, что Google закроет ваши виджеты в этом действительно действительно старом подмножестве активности.
Вместо PreferenceActivity вы должны использовать PreferenceFragments, который будет обернут в Activity (желательно ActionbarActivity, если вы хотите, чтобы ваши виджеты были затемнены).

Следуя довольно простому примеру кода, как должно выглядеть ваше действие "Настройки".

Пример

public class MySettings extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.settings_activity);

        getFragmentManager().beginTransaction()
                .replace(R.id.container, new MyPreferenceFragment()).commit();
    }

    public static class MyPreferenceFragment extends PreferenceFragment {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            addPreferencesFromResource(R.xml.preferences_file);
        }
    }
}

Примечание. В этом примере я использовал FrameLayout как мой контейнер для PreferenceFragments

Результат:

example showing tinted widgets in preferences

Итак, как вы видите, ваши виджеты будут правильно окрашены в соответствии с настройкой colorAccent.
Подробнее о PreferenceFragments на developer.android.com(щелкните).

Ответ 4

Решение, данное Tamás Szincsák, отлично работает, но оно должно быть обновлено при использовании appcompat-v7: 22.1.1 следующим образом:

импорт должен быть изменен на

import android.support.v7.widget.AppCompatCheckBox;
import android.support.v7.widget.AppCompatCheckedTextView;
import android.support.v7.widget.AppCompatEditText;
import android.support.v7.widget.AppCompatRadioButton;
import android.support.v7.widget.AppCompatSpinner;

И соответственно, переключатель должен быть

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);
}

Ответ 5

Если вы используете AppCompat, используйте элементы совместимости приложений в файле style.xml.

Например, используйте:

<style name="AppTheme" parent="Theme.AppCompat.Light">
    <item name="colorPrimary">@color/primary</item>
    <item name="colorPrimaryDark">@color/primary_dark</item>
    <item name="colorAccent">@color/accent</item>
</style>

НЕ (обратите внимание на "android:" ):

<style name="AppTheme" parent="Theme.AppCompat.Light">
    <item name="android:colorPrimary">@color/primary</item>
    <item name="android:colorPrimaryDark">@color/primary_dark</item>
    <item name="android:colorAccent">@color/accent</item>
</style>

Это исправило проблему для меня.