Làm thế nào để tham chiếu các thuộc tính style từ một drawable?


96

Tôi muốn có 2 chủ đề có thể chọn cho ứng dụng của mình. Để làm điều đó, tôi đã xác định một số thuộc tính, như sau:

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

Sau đó, tôi tạo cả hai chủ đề, như thế này:

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

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

Phương pháp này hoạt động tốt, cho phép tôi tạo và sửa đổi một số chủ đề một cách dễ dàng. Vấn đề là có vẻ như nó chỉ có thể được sử dụng trong Chế độ xem chứ không phải trong Bảng vẽ .

Ví dụ: tham chiếu một giá trị từ Chế độ xem bên trong bố cục hoạt động:

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

Nhưng làm điều tương tự trong Drawable không:

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

Tôi gặp lỗi này khi chạy ứng dụng:

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

Nếu thay vì ?item_backgroundtôi sử dụng màu mã cứng, nó sẽ hoạt động, nhưng điều đó không cho phép tôi sử dụng các chủ đề của mình. Tôi cũng đã thử ?attr:item_background, nhưng điều tương tự cũng xảy ra.

Làm thế nào tôi có thể làm điều này? Và tại sao nó hoạt động trong Chế độ xem mà không hoạt động trong Bảng vẽ? Tôi không thể tìm thấy hạn chế này ở bất kỳ đâu trong tài liệu ...


Đây có thể là một bản sao của những câu dưới đây: stackoverflow.com/questions/7529574/...
Paul Lammertsma

@Martin M., bạn đã tìm ra điều gì với điều này?
user123321 28/12/11

Bất kỳ giải pháp cho điều đó được nêu ra? Tôi đang đánh cùng tường chính xác
Guillaume

Một câu hỏi khác gần đây hơn ở đây: stackoverflow.com/q/12115125/317889 Vấn đề tương tự. Sắp xếp nó ra Google.
HGPB

3
Rõ ràng vấn đề này đã được giải quyết trong Android L xem trước, theo quy định ở đây: code.google.com/p/android/issues/detail?id=26251
Bianca Daniciuc

Câu trả lời:


161

Theo kinh nghiệm của tôi, không thể tham chiếu một thuộc tính trong một tệp XML có thể vẽ được.
Để tạo chủ đề của bạn, bạn cần:

  • Tạo một XML có thể vẽ cho mỗi chủ đề.
  • Bao gồm màu sắc cần thiết để bạn có thể vẽ trực tiếp với @colorthẻ hoặc định dạng #RGB.

Tạo một thuộc tính cho drawable của bạn trong 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>

Thêm có thể vẽ của bạn vào theme.xml của bạn .

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

Tham chiếu có thể vẽ của bạn trong bố cục của bạn bằng cách sử dụng thuộc tính của bạn.

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

20
Có vẻ như, giải pháp này vẫn cần thiết nếu bạn muốn duy trì tính tương thích ... Có từ L, nó đã được sửa và Màu chủ đề được tham chiếu tốt, nhưng cùng một mã chạy trên các thiết bị trước L khác nhau và thực tế tham chiếu đính kèm không hoạt động thiết bị pre-L! LoL .. Vì vậy, đối với tôi, nó không cố định nếu tôi phải duy trì các ngăn kéo khác nhau.
Davideas

2
Tôi ước tôi có thể ủng hộ điều này hai lần. Tôi vừa cố gắng sắp xếp hợp lý các hình dạng của mình để sử dụng tham chiếu thay vì #RGB được mã cứng và gặp lỗi tương tự. Đến SO để tìm giải pháp và tìm thấy câu trả lời giống như câu trả lời mà tôi đã bình chọn cách đây 2 tuần! (facepalm)
Tiksi

2
Đây là siêu ninja!
MariusBudin

4
ARGH! Điều này phải được ưu tiên hàng đầu để Google thực hiện một bản sửa lỗi cho! Ký hiệu? Attr-reference cực kỳ hữu ích và quan trọng đến mức gần như không thể tồn tại nếu bạn có nhiều chủ đề trong một ứng dụng. Ngay bây giờ tôi phải tạo ba XML có thể vẽ được cho mỗi loại nút tùy chỉnh!
Stephan Henningsen

2
Đó là tôi muốn. giải pháp rất đơn giản và hay trong <21 SDK.
Adnan Abdollah Zaki

20

Bắt đầu với lollipop(API 21), tính năng này được hỗ trợ, xem https://code.google.com/p/android/issues/detail?id=26251

Tuy nhiên, nếu bạn đang nhắm mục tiêu các thiết bị không có kẹo mút, đừng sử dụng nó, vì nó sẽ bị lỗi, thay vào đó hãy sử dụng giải pháp thay thế trong câu trả lời được chấp nhận.


Có bất kỳ cơ hội nào để sử dụng loại thư viện hỗ trợ để làm cho nó hoạt động trên các API trước L không?
Ivan

2
Không, thư viện hỗ trợ là một tập hợp các API có thể được sử dụng trên các thiết bị cũ hơn, sự thay đổi hành vi này nằm trong trình biên dịch và các công cụ xây dựng, vì vậy nó không liên quan đến thư viện hỗ trợ.
marmor

3
Không, trong lollipop, nó không phải là một tính năng được triển khai, mà là một bản sửa lỗi rõ ràng. Và một lỗi nghiêm trọng ở đó.
Adrian Sicaru

chết tiệt, tôi nghĩ rằng tôi đã có một giải pháp chủ đề tốt đẹp. bây giờ tôi phải quay lại và tạo một loạt các bộ chọn nút có thể kéo.
filthy_wizard

4

Mặc dù không thể tham chiếu các thuộc tính kiểu từ các tệp có thể vẽ trên các thiết bị trước Lollipop , nhưng có thể sử dụng danh sách trạng thái màu. Bạn có thể sử dụng phương thức AppCompatResources.getColorStateList (Context context, int resId) từ Thư viện hỗ trợ Android. Nhược điểm là bạn sẽ phải đặt các danh sách trạng thái màu đó theo chương trình.

Đây là một ví dụ rất cơ bản.

color / 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>

Tiện ích cần có danh sách trạng thái màu:

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

Và điều quan trọng nhất:

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

Chà, không phải là cách thanh lịch hay ngắn gọn nhất, nhưng đây là những gì Thư viện hỗ trợ Android làm để làm cho nó hoạt động trên các phiên bản cũ hơn (trước Lollipop) của Android.

Thật không may, phương pháp tương tự cho các tệp có thể kéo không hoạt động với các thuộc tính kiểu.


1

Tôi đã trả lời câu hỏi tương tự trong https://stackoverflow.com/a/59467269/3841352 nhưng tôi cũng sẽ đăng nó ở đây:

Tôi đã gặp phải vấn đề tương tự và kể từ năm 2019, nó vẫn chưa được giải quyết, vì vậy bạn không thể có một thuộc tính được tham chiếu trong bộ chọn dưới dạng có thể kéo được. Tôi sẽ chia sẻ giải pháp mà tôi nhận được cho vấn đề vì tôi không thấy nó được đăng ở đây. Tôi tìm thấy nó trong bình luận cuối cùng của báo cáo lỗi .

Cách giải quyết về cơ bản là tạo một tài nguyên có thể kéo được sẽ là tài nguyên giới thiệu giá trị thuộc tính.

Để minh họa trường hợp của bạn, giải pháp sẽ thay vì:

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

bạn sẽ thay thế? attr / * cho một tài nguyên có thể rút ra:

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

Những thứ có thể kéo được sẽ được định nghĩa là:

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>

Hy vọng nó giúp!!


0

Như @marmor đã nêu, tính năng này hiện được hỗ trợ trên API 21. Nhưng đối với những người cần hỗ trợ các phiên bản cũ của Android, bạn có thể sử dụng tính năng này. Sử dụng thư viện hỗ trợ v7, bạn vẫn có thể sử dụng nó trên các ứng dụng có cấp SDK tối thiểu đến tận 7.

Trong AppCompatImageViewThư viện hỗ trợ Android v7 có bản triển khai tính năng này không có lỗi. Đơn giản chỉ cần thay thế tập quán của bạn ImageViewbằng AppCompatImageView.


2
Nghe có vẻ hy vọng! Nhưng vấn đề là ở Hình dạng có thể vẽ không phải là Dạng xem. Tôi có chế độ xem appcompat tham chiếu (làm nền) một hình dạng sử dụng attr để có màu theo chủ đề và nó bị lỗi ở trên với lỗi <21. Có ứng dụng nào có thể vẽ được mà tôi đã bỏ qua không?
NeilS

Android 5.0.1 jy Huawei vẫn bị ảnh hưởng.
southherton
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.