【问题标题】:How to get a standard color of the neutral button如何获得中性按钮的标准颜色
【发布时间】:2018-03-19 14:17:01
【问题描述】:

我正在使用 style="?android:attr/buttonBarNeutralButtonStyle" 的按钮

<Button
    style="?android:attr/buttonBarNeutralButtonStyle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:text="Sign in" />

我想获得它的颜色,所以我也可以将它与其他视图元素一起使用。

目前我正在像这样读取它的颜色值:

int color;

View button = findViewById(R.id.passwordSigninButton);
if ((button != null) && (button instanceof Button))
  color = ((Button) button).getCurrentTextColor();
// -16738680

...它工作正常。但我更愿意直接获取与适用样式关联的颜色,而不需要使用实际按钮,以防我想在布局中没有按钮的情况下使用它。

所以我尝试了这种方法:

TypedValue typedValue = new TypedValue();

getApplicationContext().getTheme().resolveAttribute(
    android.R.attr.buttonBarNeutralButtonStyle, typedValue, true);

TypedArray typedArray = context.obtainStyledAttributes(
    typedValue.data, new int[]{android.R.attr.textColor});

int color = typedArray.getColor(0, -1);
// -1

typedArray.recycle();

但是我得到了-1,这意味着我没有得到我期望的颜色。

如何从android.R.attr.buttonBarNeutralButtonStyle 样式中获取颜色?

【问题讨论】:

  • 你的minSdkVersion 是什么。我假设它至少是 21,因为您使用的是 API 21 中引入的buttonBarNeutralButtonStyle。此外,正在使用支持库,因此您的按钮是否属于 AppCompatButton 类型?
  • @Cheticamp - 我的 minSdkVersion 是 23 岁。有关其他详细信息,请参阅 pastebin.com/raw/Xs6LCrka
  • 谢谢。您使用的是AppCompatButton 还是非兼容按钮?我认为这很重要。
  • 我在您的 pastebin 文件中看到了appcompat-v7:26.1.0,所以我假设您使用的是AppCompatButton,但您能确认一下吗?
  • @Cheticamp - 测试代码在布局中不包含任何按钮,因此应该没有任何区别。

标签: java android android-layout android-resources android-theme


【解决方案1】:

请参阅下面的直接推导更新。

您确定中性按钮文本颜色的方法是尝试复制 Android 在确定颜色时采取的步骤。正如我认为我们从对这个问题的回答中看到的那样,这种处理是在幕后进行的,并且可以随着版本的变化而变化。我敢肯定,只要结果相同,Android 开发人员可以随意更改底层实现,因此,即使您能够获得今天有效的解决方案,它也会很脆弱,明天可能会崩溃。

您确实有一个解决方案,但它涉及创建您想要避免的布局。我建议采用以下方法,我相信它会满足您的目的,会更健壮一些,并且会避免对布局文件的需要。您表明您正在使用 android.support.v7.app.AppCompatDialog 创建 AppCompatButton 按钮。

以下两行将为您提供中性按钮文本的颜色,无需布局或提取属性的复杂性。我已经在运行 API 22 的模拟器和运行 API 24 的三星 S7 上对此进行了测试,这两个结果都与使用显式布局看到的结果一致。

android.support.v7.widget.AppCompatButton button =
    new android.support.v7.widget.AppCompatButton(this, null,
    android.R.attr.buttonBarNeutralButtonStyle);
int color = button.getCurrentTextColor();

直接推导

虽然我认为上面的解决方案是最好的,但下面的代码将为所有 API 推导出中性按钮的默认颜色。这种方法只是查找textColor 属性,如果未定义,则查找textAppearance 并查看那里定义的textColor。看起来不同 API 之间的区别在于如何指定颜色。此解决方案可能足够强大,可以承受后续更新,但请注意

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        android.support.v7.widget.AppCompatButton button =
            new android.support.v7.widget.AppCompatButton(this, null, android.R.attr.buttonBarNeutralButtonStyle);
        Log.d("MainActivity", String.format("<<<< Button color = 0x%08X", button.getCurrentTextColor()));
        Log.d("MainActivity", String.format("<<<< Derived color = 0x%08X", getNeutralButtonColor(Color.WHITE)));
    }

    private int getNeutralButtonColor(int defaultColor) {
        TypedArray ta;
        int color = defaultColor;
        boolean colorFound = false;
        int textColorResId;
        final int baseAttr = R.attr.buttonBarNeutralButtonStyle;

        // Look for an explicit textColor attribute and use it if it is defined.
        ta = getTheme().obtainStyledAttributes(null, new int[]{android.R.attr.textColor}, baseAttr, 0);
        textColorResId = ta.getResourceId(0, -1);
        if (textColorResId == -1) { // try to get color if not resource id
            int type = ta.getType(0);
            if (type >= TypedValue.TYPE_FIRST_COLOR_INT && type <= TypedValue.TYPE_LAST_COLOR_INT) {
                color = ta.getColor(0, defaultColor);
                colorFound = true;
            }
        }
        ta.recycle();

        if (textColorResId == -1 && !colorFound) {
            // No color, yet. See if textAppearance is defined.
            ta = obtainStyledAttributes(null, new int[]{android.R.attr.textAppearance},
                                        baseAttr, 0);
            int textAppearanceId = ta.getResourceId(0, -1);
            if (textAppearanceId != -1) {
                // OK, textAppearance is defined. Get the embedded textColor.
                ta.recycle();
                ta = obtainStyledAttributes(textAppearanceId, new int[]{android.R.attr.textColor});
                textColorResId = ta.getResourceId(0, -1);
                if (textColorResId == -1) { // try to get color if not resource id
                    int type = ta.getType(0);
                    if (type >= TypedValue.TYPE_FIRST_COLOR_INT && type <= TypedValue.TYPE_LAST_COLOR_INT) {
                        color = ta.getColor(0, defaultColor);
                        colorFound = true;
                    }
                }
            }
            ta.recycle();
        }

        if (textColorResId != -1 && !colorFound) {
            ColorStateList colorStateList = AppCompatResources.getColorStateList(this, textColorResId);
            if (colorStateList != null) {
                color = colorStateList.getDefaultColor();
                colorFound = true; // in case needed later
            }
        }

        return color;
    }

    @SuppressWarnings("unused")
    private static final String TAG = "MainActivity";
}

【讨论】:

  • @Ωmega 我确信有一种直接的方法,但它可能涉及深入挖掘代码以了解正在发生的事情,而且正如我所提到的,它会很脆弱。我认为这是更好的方法,因为您将使用 Android 自己的内部处理来实现所需的目的,而不会增加布局文件的复杂性。
  • @Ωmega 查看更新以回答。如果有帮助,我可以合并 API 23 解决方案。
  • 我喜欢它,但是为什么您的 API 24+ 解决方案不适用于 API 23?稍微挖掘一下就可以找到原因。否则,在不知不觉中,我们冒着使用下一级 API 可能会面临类似/新问题的风险。
  • 我了解textColorResId 未在 API 23 及更低版本的android.R.attr.buttonBarNeutralButtonStyle 内为android.R.attr.textColor 定义,但/为什么textAppearanceandroid.R.attr.textColor 仅针对 API 23 及更低版本定义对我来说没有意义
  • @Ωmega 所以,我已经破解了密码。我已经更新了答案以识别颜色何时是特定值而不是参考,并在主题中覆盖 buttonBarNeutralButtonStyle 的本机定义时识别正确的颜色。
【解决方案2】:

您可以在项目的 values 文件夹中创建 colors.xml 并定义要用于视图的颜色。例如:

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <color name="white">#FFFFFF</color>
 <color name="green">#008000</color>
 <color name="blue">#0000FF</color>
 <color name="black">#000000</color>
</resources>

然后在您的样式中,参考此文件中的颜色:

例如:

<style name="ButtonColor" parent="@android:style/Widget.Button">
   <item name="android:textColor">@color/blue</item>
</style> 

那么对于任何其他你想要颜色的元素,你不需要依赖于一个视图,只需从这个 colors.xml 访问

textView.setTextColor(getResources().getColor(R.color.blue));

但如果你想真正从样式中访问它:

// The attributes you want retrieved
int[] attrs = {android.R.attr.textColor, android.R.attr.text};

// Parse style
TypedArray typedArray  = obtainStyledAttributes(R.style.stylename, attrs);

// Get color from style
int textColor = typedArray.getColor(0, "default color");

//Check by priting
Log("Retrieved textColor as hex:", Integer.toHexString(textColor));

//recycle
typedArray.recycle()

【讨论】:

    【解决方案3】:

    我运行了您上面给出的相同代码。我能够得到一个整数值。

    输出:System.out:打印颜色int值:-49023

    import android.content.res.TypedArray;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.util.TypedValue;
    
     public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            TypedValue typedValue = new TypedValue();
    
            getApplicationContext().getTheme().resolveAttribute(
                    android.R.attr.buttonBarNeutralButtonStyle, typedValue, true);
    
            TypedArray typedArray = this.obtainStyledAttributes(
                    typedValue.data, new int[]{android.R.attr.textColor});
    
            int color = typedArray.getColor(0, -1);
            System.out.println("Printing the color int value: " + color);
    
            typedArray.recycle();
        }
    }
    

    下面的代码有不同的风格:

     getApplicationContext().getTheme().resolveAttribute(
                        android.R.attr.actionButtonStyle, typedValue, true);
    
     TypedArray typedArray = this.obtainStyledAttributes(
                        typedValue.data, new int[]{android.R.attr.colorForeground});
    
     int color = typedArray.getColor(0, -1);
     System.out.println("Printing the color int value: " + color);
    

    输出:System.out:打印颜色int值:-16777216


    我使用的是 Android Studio 3.0.1 构建 #AI-171.4443003,构建于 2017 年 11 月 9 日 JRE:1.8.0_152-release-915-b08 x86_64 JVM:JetBrains s.r.o 的 OpenJDK 64 位服务器 VM Mac OS X 10.13.3

    【讨论】:

    • 我已经打印了我得到的输出。我不确定你的情况可能是什么问题。你试过同样的代码吗?
    猜你喜欢
    • 2021-08-12
    • 1970-01-01
    • 1970-01-01
    • 2021-10-13
    • 2018-07-27
    • 2010-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多