จะอ้างอิงแอตทริบิวต์สไตล์จาก drawable ได้อย่างไร?


99

ฉันต้องการมี 2 ธีมที่เลือกได้สำหรับแอปพลิเคชันของฉัน ในการทำเช่นนั้นฉันได้กำหนดคุณลักษณะบางอย่างดังนี้:

 <attr format="color" name="item_background" />

จากนั้นฉันสร้างทั้งสองธีมดังนี้:

  <style name="ThemeA">
     <item name="item_background">#123456</item>
 </style>

 <style name="ThemeB">
     <item name="item_background">#ABCDEF</item>
 </style>

วิธีนี้ใช้ได้ผลดีทำให้ฉันสร้างและปรับเปลี่ยนธีมต่างๆได้อย่างง่ายดาย ปัญหาคือว่าดูเหมือนว่ามันสามารถนำมาใช้เฉพาะในการเข้าชมและไม่อยู่ใน Drawables

ตัวอย่างเช่นการอ้างอิงค่าจากมุมมองภายในเค้าโครงใช้งานได้:

 <TextView android:background="?item_background" />

แต่การทำเช่นเดียวกันใน Drawable ไม่ได้:

 <shape android:shape="rectangle">
     <solid android:color="?item_background" />
 </shape>

ฉันได้รับข้อผิดพลาดนี้เมื่อเรียกใช้แอปพลิเคชัน:

    java.lang.UnsupportedOperationException: Can't convert to color: type=0x2

ถ้า?item_backgroundฉันใช้สีฮาร์ดโค้ดแทนมันก็ใช้ได้ แต่ไม่อนุญาตให้ฉันใช้ธีมของฉัน ฉันก็พยายาม?attr:item_backgroundเหมือนกัน แต่สิ่งเดียวกันก็เกิดขึ้น

ฉันจะทำสิ่งนี้ได้อย่างไร? และเหตุใดจึงทำงานใน Views แต่ใช้ไม่ได้ใน Drawables ฉันไม่พบข้อ จำกัด นี้ในเอกสาร ...


คำถามนี้อาจซ้ำกับคำถามต่อไปนี้stackoverflow.com/questions/7529574/…
Paul Lammertsma

@Martin M. คุณคิดอย่างไรกับเรื่องนี้?
user123321

วิธีแก้ปัญหาสำหรับสิ่งนั้นหรือยัง? ฉันชนกำแพงเดียวกัน
เป๊ะ

อีกคำถามล่าสุดที่นี่: stackoverflow.com/q/12115125/317889ปัญหาเดียวกัน จัดเรียงออกจาก Google
HGPB

3
เห็นได้ชัดว่าปัญหานี้ได้รับการแก้ไขแล้วในการแสดงตัวอย่าง Android L ตามที่ระบุไว้ที่นี่: code.google.com/p/android/issues/detail?id=26251
Bianca Daniciuc

คำตอบ:


167

จากประสบการณ์ของฉันมันเป็นไปไม่ได้ที่จะอ้างอิงแอตทริบิวต์ใน XML drawable
ในการสร้างธีมของคุณคุณต้อง:

  • สร้าง XML ที่วาดได้หนึ่งรายการต่อธีม
  • รวมสีที่ต้องการลงในที่คุณวาดได้โดยตรงด้วย@colorแท็กหรือรูปแบบ #RGB

ทำให้แอตทริบิวต์สำหรับ drawable คุณในattrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
   <!-- Attributes must be lowercase as we want to use them for drawables -->
   <attr name="my_drawable" format="reference" />
</resources>

เพิ่ม drawable ของคุณไปยังtheme.xml

<style name="MyTheme" parent="@android:style/Theme.NoTitleBar">
   <item name="my_drawable">@drawable/my_drawable</item>
</style>

อ้างอิง drawable ของคุณในเค้าโครงของคุณโดยใช้แอตทริบิวต์ของคุณ

<TextView android:background="?my_drawable" />

21
ดูเหมือนว่าโซลูชันนี้ยังคงจำเป็นหากคุณต้องการให้ความเข้ากันได้ ... ใช่จาก L ได้รับการแก้ไขและสีของธีมได้รับการอ้างอิงอย่างดี แต่รหัสเดียวกันทำงานบนอุปกรณ์ pre-L ที่แตกต่างกันและการอ้างอิง attr ไม่ทำงาน อุปกรณ์ pre-L! LoL .. ดังนั้นสำหรับฉันแล้วมันไม่ได้รับการแก้ไขถ้าฉันต้องดูแล drawables ต่างๆต่อไป
Davideas

2
ฉันหวังว่าฉันจะโหวตเพิ่มอีกสองครั้ง เพิ่งพยายามปรับปรุงรูปร่างของฉันเพื่อใช้การอ้างอิงแทน #RGB แบบฮาร์ดโค้ดและได้รับข้อผิดพลาดเดียวกัน มาที่ SO เพื่อหาวิธีแก้ปัญหาและพบคำตอบเดียวกันกับที่ฉันโหวตเมื่อ 2 สัปดาห์ก่อน! (facepalm)
Tiksi

2
นี่คือซุปเปอร์นินจา!
MariusBudin

4
ARGH! สิ่งนี้ควรมีความสำคัญสูงสุดสำหรับ Google ในการแก้ไขแบ็คพอร์ต! สัญกรณ์? attr-reference มีประโยชน์และสำคัญมากจนแทบจะเป็นไปไม่ได้เลยหากคุณมีหลายธีมภายในแอพ ตอนนี้ฉันต้องสร้าง XML ที่วาดได้สามแบบสำหรับปุ่มแบบกำหนดเองแต่ละประเภท!
Stephan Henningsen

2
นั่นคือฉันต้องการ วิธีแก้ปัญหาที่ง่ายและดีใน <21 SDK
Adnan Abdollah Zaki

20

ตั้งแต่lollipop(API 21) รองรับคุณลักษณะนี้โปรดดู https://code.google.com/p/android/issues/detail?id=26251

อย่างไรก็ตามหากคุณกำหนดเป้าหมายอุปกรณ์ที่ไม่มีอมยิ้มอย่าใช้เพราะจะขัดข้องให้ใช้วิธีแก้ปัญหาในคำตอบที่ยอมรับแทน


มีโอกาสที่จะใช้ไลบรารีการสนับสนุนเพื่อให้ใช้งานได้กับ Pre L APIs หรือไม่?
Ivan

2
ไม่ไลบรารีการสนับสนุนคือชุดของ API ที่สามารถใช้กับอุปกรณ์รุ่นเก่าการเปลี่ยนแปลงลักษณะการทำงานนี้อยู่ในคอมไพเลอร์และเครื่องมือสร้างดังนั้นจึงไม่เกี่ยวข้องกับไลบรารีการสนับสนุน
marmor

3
ไม่ในอมยิ้มมันไม่ใช่ฟีเจอร์ที่ใช้งานได้ แต่เป็นการแก้ไขข้อบกพร่องที่เห็นได้ชัด และจุดบกพร่องร้ายแรงที่
Adrian Sicaru

เหี้ยฉันคิดว่าฉันมีวิธีแก้ปัญหาที่ดี ตอนนี้ฉันต้องกลับไปสร้างปุ่มเลือกตัวเลือกปุ่มมากมาย
filthy_wizard

4

แม้ว่าจะไม่สามารถอ้างอิงแอตทริบิวต์สไตล์จาก drawables บนอุปกรณ์pre-Lollipopได้ แต่ก็เป็นไปได้สำหรับรายการสถานะสี คุณสามารถใช้วิธีAppCompatResources.getColorStateList (บริบทบริบท, int resId)จาก Android Support Library ข้อเสียคือคุณจะต้องตั้งค่ารายการสถานะสีเหล่านั้นโดยใช้โปรแกรม

นี่คือตัวอย่างพื้นฐาน

สี / my_color_state.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_checked="true" android:color="?colorControlActivated" />
  <item android:color="?colorControlNormal" />
</selector>

วิดเจ็ตที่ต้องการรายการสถานะสี:

<RadioButton
  android:id="@+id/radio_button"
  android:text="My Radio" />

และที่สำคัญที่สุด:

ColorStateList csl = AppCompatResources.getColorStateList(context, R.color.my_color_state);    
RadioButton r = (RadioButton) findViewById(R.id.radio_button);
r.setTextColor(csl);

ไม่ใช่วิธีที่หรูหราที่สุดหรือสั้นที่สุด แต่นี่คือสิ่งที่ Android Support Library ทำเพื่อให้สามารถใช้งานได้กับ Android เวอร์ชันเก่า (ก่อน Lollipop)

น่าเสียดายที่วิธีการเดียวกันสำหรับ drawables ใช้ไม่ได้กับแอตทริบิวต์สไตล์


3

ฉันตอบคำถามเดียวกันในhttps://stackoverflow.com/a/59467269/3841352แต่ฉันจะโพสต์ไว้ที่นี่เช่นกัน:

ฉันพบปัญหาเดียวกันและในปี 2019 ยังไม่ได้รับการแก้ไขดังนั้นคุณจึงไม่สามารถมีแอตทริบิวต์ที่อ้างอิงในตัวเลือกเป็นแบบ drawable ได้ ฉันจะแบ่งปันวิธีแก้ปัญหาที่ฉันพบเนื่องจากไม่เห็นโพสต์ไว้ที่นี่ ผมพบว่ามันอยู่ในความคิดเห็นล่าสุดของรายงานข้อผิดพลาด

วิธีแก้ปัญหาเบื้องต้นคือการสร้างทรัพยากรที่ดึงได้ซึ่งจะเป็นทรัพยากรที่อ้างถึงค่าแอตทริบิวต์

เพื่ออธิบายกรณีของคุณวิธีแก้ปัญหาจะเป็นแทน:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="?attr/colorPrimary" android:state_enabled="true" android:state_window_focused="false"/>
    <item android:drawable="?attr/colorPrimaryDark" android:state_pressed="true"/>
    <item android:drawable="@android:color/darker_gray" android:state_enabled="false"/>
    <item android:drawable="?attr/colorPrimary"/>
</selector>

คุณจะแทนที่? attr / * สำหรับทรัพยากรที่ดึงได้:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/colorPrimaryDrawable" android:state_enabled="true" android:state_window_focused="false"/>
    <item android:drawable="@drawable/colorPrimaryDarkDrawable" android:state_pressed="true"/>
    <item android:drawable="@android:color/darker_gray" android:state_enabled="false"/>
    <item android:drawable="@drawable/colorPrimaryDrawable"/>
</selector>

drawables จะถูกกำหนดเป็น:

drawable / colorPrimaryDrawable

<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle">
    <solid android:color="?attr/colorPrimary" />
</shape>

drawable / colorPrimaryDarkDrawable

<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle">
    <solid android:color="?attr/colorPrimaryDark" />
</shape>

หวังว่าจะช่วย !!


0

ตามที่ @marmor ระบุว่าตอนนี้รองรับ API 21 แล้ว แต่สำหรับผู้ที่ต้องการรองรับ Android เวอร์ชันเดิมคุณสามารถใช้คุณลักษณะนี้ได้ การใช้ไลบรารีการสนับสนุน v7 คุณยังสามารถใช้กับแอปที่มีระดับ SDK ขั้นต่ำได้จนถึง 7

AppCompatImageViewใน v7 ห้องสมุดสนับสนุน Android มีข้อผิดพลาดการดำเนินงานฟรีของคุณลักษณะนี้ เพียงแทนที่ประเพณีของคุณด้วยImageViewAppCompatImageView


2
ฟังดูมีความหวัง! แต่ปัญหาอยู่ในรูปร่างที่วาดได้ไม่ใช่มุมมอง ฉันมีมุมมอง appcompat ที่อ้างอิง (เป็นพื้นหลัง) รูปร่างที่ใช้ attr เพื่อให้ได้สีตามธีมและมันก็ตรงกับข้อผิดพลาดข้างต้นใน <21 มี appcompat ที่ฉันพลาดไปหรือไม่?
NeilS

Android 5.0.1 jy Huawei ยังคงได้รับผลกระทบ
southerton
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.