รับค่าสีทางโปรแกรมเมื่อเป็นข้อมูลอ้างอิง (ธีม)


116

พิจารณาสิ่งนี้:

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>

ดังนั้นสีของชุดรูปแบบจะถูกอ้างอิงโดยธีม ฉันจะรับ theme_color (การอ้างอิง) แบบเป็นโปรแกรมได้อย่างไร ปกติฉันจะใช้getResources().getColor()แต่ไม่ใช่ในกรณีนี้เพราะอ้างอิง!

คำตอบ:


257

สิ่งนี้ควรทำงาน:

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

และอย่าลืมใช้ธีมนี้กับกิจกรรมของคุณก่อนที่จะเรียกรหัสนี้ ใช้อย่างใดอย่างหนึ่ง:

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

ในรายการหรือการโทรของคุณ (ก่อนที่คุณจะโทรsetContentView(int)):

setTheme(R.style.Theme_BlueTheme)

ในonCreate().

ฉันได้ทดสอบกับค่าของคุณแล้วและทำงานได้อย่างสมบูรณ์


ขอบคุณฉันไม่สามารถลองวิธีแก้ปัญหาของคุณได้เพราะฉันได้รับข้อผิดพลาด: stackoverflow.com/questions/17278244/…บางทีคุณอาจมีประสบการณ์ในเรื่องนี้ ...
Seraphim's

5
อย่างไรก็ตามด้วยวิธีการแก้ปัญหาของคุณฉันได้สีค่า 0 (TypedValue {t = 0x0 / d = 0x0}) ... ฉันไม่ได้ใช้รูปแบบที่ประกาศได้เพียงแค่การอ้างอิงถึงสี
Seraphim's

คุณใช้ธีมกับกิจกรรมของคุณหรือไม่?
Emanuel Moecklin

5
หากคุณไม่ต้องการใช้ธีมกับกิจกรรมคุณสามารถสร้างContextThemeWrapperโดยใช้รหัสธีมจากนั้นดึงธีมจากนั้น
Ted Hopp

1
วิธีนี้ใช้ได้กับ Android X (การออกแบบวัสดุ)
blacklind

43

หากต้องการเพิ่มคำตอบที่ยอมรับหากคุณใช้ kotlin

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

จากนั้นในกิจกรรมของคุณคุณสามารถทำได้

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


2
โอเคขอบคุณสำหรับ "การรวม" ฉันไม่ได้ใช้ kotlin แต่มันน่าสนใจ
Seraphim

5
มันทำให้ TypedValue มองเห็นได้กับโลกภายนอก และสำหรับสีคุณมักต้องการแก้ไขการประกาศอ้างอิงดังนั้นฉันจึงมีสิ่งนี้: @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = TypedValue().let { theme.resolveAttribute(attribute, it, true); it.data }(มีรูปแบบไม่ดีที่นี่ แต่ก็โอเค)
milosmns

1
การใช้งานจะเป็นดังนี้val errorColor = context.getThemeColor(R.attr.colorError)
milosmns

วิธีที่เป็นสากลมากขึ้นซึ่งจะดึงค่าเริ่มต้นสำหรับColorStateList: @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = obtainStyledAttributes(intArrayOf(attribute)).use { it.getColor(0, Color.MAGENTA) }(จากNick Butcher )
gmk57

วิธีที่ดีที่สุดซึ่งดึงข้อมูลทั้งหมดColorStateListแม้ว่าจะอ้างถึงคุณลักษณะของธีมอื่น: fun Context.getThemeColor(@AttrRes attribute: Int): ColorStateList = TypedValue().let { theme.resolveAttribute(attribute, it, true); AppCompatResources.getColorStateList(this, it.resourceId) }(สีเดียวจะถูกรวมไว้ColorStateListด้วย)
gmk57

24

สิ่งนี้ใช้ได้ผลสำหรับฉัน:

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

หากคุณต้องการดึง hexstring ออกมา:

Integer.toHexString(color)

สิ่งนี้ควรส่งคืน ColorRes ไม่ใช่ ColorInt
Miha_x64

ฉันลงเอยด้วยการใช้ getColorResource (สี) และไม่เรียกรีไซเคิล
Zeek Aran

2

หากคุณต้องการได้หลายสีคุณสามารถใช้:

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

เพิ่มสิ่งนี้ใน build.gradle (แอป) ของคุณ:

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

และเพิ่มฟังก์ชันส่วนขยายนี้ไว้ที่ใดที่หนึ่งในโค้ดของคุณ:

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

0

ต่อไปนี้เป็นวิธียูทิลิตี้ Java แบบรวบรัดที่รับแอตทริบิวต์หลายรายการและส่งคืนอาร์เรย์ของจำนวนเต็มสี :)

/**
 * @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 ดีกว่า Kotlin สำหรับสิ่งนี้หรือไม่?
IgorGanapolsky

@IgorGanapolsky โอ้ฉันไม่รู้จริงๆ ฉันแชร์รหัสของฉันตั้งแต่ฉันรู้ว่าจะมีประโยชน์กับใครบางคนที่นั่น ฉันไม่รู้จัก Kotlin และฉันคิดว่า Kotlin จะไม่ทำให้มันทำงานได้ดีขึ้นอาจจะมีโค้ดน้อยลง! : P
varun

-1

สำหรับผู้ที่กำลังมองหาการอ้างอิงถึง drawable คุณควรใช้falseในresolveRefs

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


ตัวแปร typedValue อ้างอิงถึงอะไร
BENN1TH

ธีมตัวแปรคืออะไร * อ้างอิงถึง?
BENN1TH
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.