Nhận giá trị màu theo chương trình khi đó là một tham chiếu (chủ đề)


116

Xem xét điều này:

styles.xml

<style name="BlueTheme" parent="@android:style/Theme.Black.NoTitleBar">
    <item name="theme_color">@color/theme_color_blue</item>
</style>

attrs.xml

<attr name="theme_color" format="reference" />

color.xml

<color name="theme_color_blue">#ff0071d3</color>

Vì vậy, màu chủ đề được tham chiếu bởi chủ đề. Làm cách nào để tải theme_color (tham chiếu) theo chương trình? Thông thường tôi sẽ sử dụng getResources().getColor()nhưng không phải trong trường hợp này vì nó được tham chiếu!

Câu trả lời:


255

Điều này sẽ thực hiện công việc:

TypedValue typedValue = new TypedValue();
Theme theme = context.getTheme();
theme.resolveAttribute(R.attr.theme_color, typedValue, true);
@ColorInt int color = typedValue.data;

Ngoài ra, hãy đảm bảo áp dụng chủ đề cho Hoạt động của bạn trước khi gọi mã này. Sử dụng:

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

trong tệp kê khai hoặc cuộc gọi của bạn (trước khi bạn gọi setContentView(int)):

setTheme(R.style.Theme_BlueTheme)

trong onCreate().

Tôi đã thử nghiệm nó với các giá trị của bạn và nó hoạt động hoàn hảo.


cảm ơn Tôi chưa thể thử giải pháp của bạn vì tôi gặp lỗi: stackoverflow.com/questions/17278244/… Có thể bạn có kinh nghiệm trong việc này ...
Seraphim's

5
Dù sao, với giải pháp của bạn, tôi nhận được màu giá trị 0 (TypedValue {t = 0x0 / d = 0x0}) ... Tôi không sử dụng kiểu có thể khai báo, chỉ là tham chiếu đến màu
Seraphim's

Bạn có áp dụng chủ đề cho hoạt động của mình không?
Emanuel Moecklin

5
Nếu bạn không muốn áp dụng chủ đề cho hoạt động, bạn có thể tạo một ContextThemeWrapperchủ đề bằng cách sử dụng id chủ đề và sau đó truy xuất chủ đề từ đó.
Ted Hopp

1
Phương pháp này hoạt động trong android X (thiết kế
material design

43

Để thêm vào câu trả lời được chấp nhận, nếu bạn đang sử dụng kotlin.

@ColorInt
fun Context.getColorFromAttr(
    @AttrRes attrColor: Int,
    typedValue: TypedValue = TypedValue(),
    resolveRefs: Boolean = true
): Int {
    theme.resolveAttribute(attrColor, typedValue, resolveRefs)
    return typedValue.data
}

và sau đó trong hoạt động của bạn, bạn có thể làm

textView.setTextColor(getColorFromAttr(R.attr.color))


2
oook, cảm ơn vì "tích hợp". Tôi không sử dụng kotlin nhưng nó rất thú vị.
Seraphim là

5
Nó làm cho TypedValue hiển thị với thế giới bên ngoài. Và đối với màu sắc, bạn luôn muốn giải quyết các khai báo tham chiếu, vì vậy tôi có điều này: @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = TypedValue().let { theme.resolveAttribute(attribute, it, true); it.data }(định dạng kém ở đây nhưng không sao)
milosmns 17/02/19

1
Cách sử dụng sẽ như thế này:val errorColor = context.getThemeColor(R.attr.colorError)
milosmns

Cách phổ biến hơn, cũng truy xuất giá trị mặc định cho ColorStateList: @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = obtainStyledAttributes(intArrayOf(attribute)).use { it.getColor(0, Color.MAGENTA) }(từ Nick Butcher )
gmk57

Cách cuối cùng, lấy toàn bộ ColorStateList, ngay cả khi nó tham chiếu đến các thuộc tính chủ đề khác: fun Context.getThemeColor(@AttrRes attribute: Int): ColorStateList = TypedValue().let { theme.resolveAttribute(attribute, it, true); AppCompatResources.getColorStateList(this, it.resourceId) }(các màu đơn cũng sẽ được bao bọc trong một ColorStateList).
gmk57

24

Điều này đã làm việc cho tôi:

int[] attrs = {R.attr.my_attribute};
TypedArray ta = context.obtainStyledAttributes(attrs);
int color = ta.getResourceId(0, android.R.color.black);
ta.recycle();

nếu bạn muốn lấy chuỗi lục ra khỏi nó:

Integer.toHexString(color)

Điều này sẽ trả về ColorRes, không phải ColorInt.
Miha_x64,

Tôi đã kết thúc bằng cách sử dụng này với getColorResource (màu) và không gọi Recycle.
Zeek Aran

2

Nếu bạn muốn có nhiều màu, bạn có thể sử dụng:

int[] attrs = {R.attr.customAttr, android.R.attr.textColorSecondary, 
        android.R.attr.textColorPrimaryInverse};
Resources.Theme theme = context.getTheme();
TypedArray ta = theme.obtainStyledAttributes(attrs);

int[] colors = new int[attrs.length];
for (int i = 0; i < attrs.length; i++) {
    colors[i] = ta.getColor(i, 0);
}

ta.recycle();

2

Thêm cái này vào build.gradle (ứng dụng) của bạn:

implementation 'androidx.core:core-ktx:1.1.0'

Và thêm chức năng mở rộng này vào đâu đó trong mã của bạn:

@ColorInt
@SuppressLint("Recycle")
fun Context.themeColor(
    @AttrRes themeAttrId: Int
): Int {
    return obtainStyledAttributes(
        intArrayOf(themeAttrId)
    ).use {
        it.getColor(0, Color.MAGENTA)
    }
}

0

Đây là một phương thức tiện ích Java ngắn gọn lấy nhiều thuộc tính và trả về một mảng các số nguyên màu. :)

/**
 * @param context    Pass the activity context, not the application context
 * @param attrFields The attribute references to be resolved
 * @return int array of color values
 */
@ColorInt
static int[] getColorsFromAttrs(Context context, @AttrRes int... attrFields) {
    int length = attrFields.length;
    Resources.Theme theme = context.getTheme();
    TypedValue typedValue = new TypedValue();

    @ColorInt int[] colorValues = new int[length];

    for (int i = 0; i < length; ++i) {
        @AttrRes int attr = attrFields[i];
        theme.resolveAttribute(attr, typedValue, true);
        colorValues[i] = typedValue.data;
    }

    return colorValues;
}

Java tốt hơn Kotlin về điều này?
IgorGanapolsky

@IgorGanapolsky Ồ, tôi thực sự không biết. Tôi đã chia sẻ mã của mình vì tôi biết nó sẽ có ích cho ai đó ngoài kia! Tôi không biết Kotlin và tôi cho rằng Kotlin sẽ không làm cho nó hoạt động tốt hơn, có thể ít dòng mã hơn! : P
varun

-1

Đối với những người đang tìm kiếm tài liệu tham khảo để có thể vẽ bạn nên sử dụng falsetrongresolveRefs

theme.resolveAttribute(R.attr.some_drawable, typedValue, **false**);


Biến typedValue liên quan đến là gì?
BENN1TH

Chủ đề biến. * Liên quan đến là gì?
BENN1TH
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.