使用AppCompat v21为PreferenceActivity小部件应用色调

16
我正在使用PreferenceActivity中的CheckboxPreference和v21支持库中的AppCompat主题。正如您所知,使用此最新库时,像复选框、编辑框、单选按钮等小部件都会使用主题中定义的次要颜色进行着色。在首选项屏幕中,文本以我的主题指定的正确颜色显示,但是复选框和编辑框却没有。似乎当CheckboxPreference实例创建小部件时,它不会将我的主题应用于它。
普通布局中着色的单选按钮:

screenshot 1

复选框来自CheckboxPreference,未着色:

screenshot 2

我正在使用Theme.AppCompat.Light.NoActionBar作为父主题。这会影响Preference的每个子类,如EditTextPreference,其中EditText具有黑色底线而不是着色底线。我该如何将颜色应用于Preference子类显示的小部件?
更新:未应用着色,因为PreferenceActivity扩展了框架Activity。在工作情况下,我正在使用支持库中的ActionBarActivity。现在的问题是:为什么?

5
我在小部件着色和复选框小部件方面也遇到了问题。我正在ActionBarActivity布局中使用CheckBox控件,但无法进行着色。我只能得到默认的黑色方块。很糟糕。 - Gordon Freeman
此外,官方已经声明这是按预期工作的(请参见末尾的常见问题解答)http://android-developers.blogspot.it/2014/10/appcompat-v21-material-design-for-pre.html?m=1 - devrocca
我在我的首选项活动中使用了ActionBarActivity,并且复选框上的色调效果正常。但是在ListPreference内部,复选框没有着色,只有在单击后才会出现... - Wakim
5个回答

10

编辑:从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.javaActionBarActivityDelegateBase.java以获取原始代码。

6
我知道这个问题有点老了,但我想留下一个解决方案来解决您所遇到的问题。首先,我想说PreferenceActivity是蜂窝前时代的遗物,因此不要期望Google会在这个非常古老的Activity子集中对您的小部件进行着色。
您应该使用PreferenceFragments代替PreferenceActivity,它们将被包装在一个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(点击)


谢谢您的回答,但是该应用程序的minSDK为10,所以即使我知道PreferenceActivity已经被弃用,我也必须使用它。 - devrocca
1
我同时使用ActionBarActivity和PreferenceFragment的组合,当通过资源添加时它可以正常工作。然而,任何通过代码动态实例化的CheckBoxPreference仍然会产生黑色复选框。 - Q''
1
@Q'' 这是正常的。支持的小部件将在填充期间被拦截并正确着色。如果您动态添加了某些内容,则不会发生这种情况。作为参考,您可以收听此播客(点击),特别是从第7分25秒开始的部分。 - reVerse
1
@devrocca 在这种情况下,您应该使用两个不同的活动。 ;) 没有必要完全支持这些超级老的版本。 - reVerse
复选框对我来说可以工作,但开关和列表偏好设置无法工作。 - Nathan Schwermann
据我所知,只有在使用android.support.v7.widget.SwitchCompat时才会对开关进行着色,而SwitchPreference并不使用它。因此,唯一的选择是自己实现一个SwitchPreference。至于列表偏好设置,可能是因为它显示在对话框中的原因。 - reVerse

2

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

2

到目前为止,我自己(很悲伤)的解决方法是从头开始创建自己的复选框可绘制对象,使用应该在第一次着色时应该着色的颜色。

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

drawable/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>
< p >checkbox_oncheckbox_off是选中和未选中状态的PNG可绘制对象,每个屏幕密度显然需要一个。 如果您关心尺寸一致性,则可绘制对象的基准(MDPI)尺寸应为32px完整资产和18px光学正方形。


我接受了这个回答,因为它与问题和PreferenceActivity的使用有关。然而,由于该Activity已被弃用,最好的方法是使用PreferenceFragment,就像reVerse的回答中所述。 - devrocca
我最终采用了你的解决方案,在我的情况下转移到PreferenceFragment太过繁琐。 - NeviQ-OR

1
如果你使用AppCompat,则需要在style.xml文件中使用app compat项。
例如,使用:
<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>

这对我解决了问题。

1
这是正确的,但是它不能与PreferenceActivity一起使用,因为开发人员指出,该过时的Activity不使用能够在自身上应用色调的AppCompat小部件。它可以与PreferenceFragment一起使用,这可能是您正在使用的内容。 - devrocca
是的,我正在使用PreferenceFragment。感谢devrocca的澄清。 - TALE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接