드로어 블에서 스타일 속성을 참조하는 방법은 무엇입니까?


96

내 응용 프로그램에 대해 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>

이 방법은 훌륭하게 작동하여 여러 테마를 쉽게 만들고 수정할 수 있습니다. 문제는 드로어 블이 아닌 뷰에서만 사용할 수 있다는 것입니다 .

예를 들어 레이아웃 내에서보기의 값을 참조하면 다음과 같이 작동합니다.

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

하지만 드로어 블에서 똑같이하는 것은 다음과 같습니다.

 <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했지만 같은 일이 발생합니다.

어떻게 할 수 있습니까? 뷰에서는 작동하지만 드로어 블에서는 작동하지 않는 이유는 무엇입니까? 문서 에서이 제한을 찾을 수 없습니다 ...


: 이것은 다음과 같은 질문의 중복 될 수 stackoverflow.com/questions/7529574/...
— 폴 Lammertsma

@Martin M., 이것으로 무엇을 알아 냈습니까?
— user123321 dec.

아직 해결책이 없습니까? 나는 똑같은 벽
— Guillaume

또 다른 최근 질문 : stackoverflow.com/q/12115125/317889 같은 문제입니다. Google에서 정렬하십시오.
— HGPB 2012 년

3
여기에 지정된대로 분명히이 문제는 안드로이드 L 미리보기에서 해결되었다 : code.google.com/p/android/issues/detail?id=26251
— 비앙카 Daniciuc

답변:


161

내 경험상 XML 드로어 블의 속성을 참조하는 것은 불가능합니다.
테마를 만들려면 다음이 필요합니다.

  • 테마 당 하나의 XML 드로어 블을 만듭니다.
  • @color태그 또는 #RGB 형식을 사용 하여 필요한 색상을 드로어 블에 직접 포함 합니다.

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>

드로어 블을 theme.xml에 추가하십시오 .

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

속성을 사용하여 레이아웃에서 드로어 블을 참조하십시오.

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

20
호환성을 유지하려면이 솔루션이 여전히 필요한 것 같습니다 ... 예 L에서 고정되어 있고 테마 색상이 잘 참조되지만 동일한 코드가 다른 pre-L 장치에서 실행되고 실제로 attr 참조가 작동하지 않습니다. pre-L 장치! LoL .. 그래서 어쨌든 다른 드로어 블을 유지해야한다면 그것은 고정되어 있지 않습니다.
— Davideas

2
나는 이것을 두 번 찬성 할 수 있으면 좋겠다. 하드 코딩 된 #RGB 대신 참조를 사용하도록 내 셰이프를 간소화하려고했는데 동일한 오류가 발생했습니다. 해결책을 찾기 위해 왔고 2 주 전에 upvoted와 동일한 답변을 찾았습니다! (facepalm)
— Tiksi

2
이것은 슈퍼 닌자입니다!
— MariusBudin

4
아아! 이것은 Google이 백 포트 수정을 수행하는 데 최우선 순위 여야합니다! ? attr-reference 표기법은 매우 유용하고 중요하여 앱 내에 여러 테마가있는 경우 없이는 살 수 없을 정도로 매우 유용합니다. 지금 당장은 각 사용자 정의 버튼 유형에 대해 3 개의 드로어 블 XML을 만들어야합니다!
— Stephan Henningsen

2
그게 내가 원하는거야. <21 SDK의 매우 간단하고 멋진 솔루션입니다.
— Adnan Abdollah Zaki

20

시작 lollipop이 기능이 지원됩니다 (API 21)을 참조 https://code.google.com/p/android/issues/detail?id=26251

그러나 롤리팝이없는 장치를 대상으로하는 경우 충돌이 발생하므로 사용하지 마십시오. 대신 허용 된 답변의 해결 방법을 사용하십시오.


사전 L API에서 작동하도록 지원 라이브러리의 종류를 사용할 기회가 있습니까?
— 이반

2
아니요, 지원 라이브러리는 이전 기기에서 사용할 수있는 API 세트입니다.이 동작 변경은 컴파일러 및 빌드 도구에 있으므로 지원 라이브러리와 관련이 없습니다.
— marmor

3
아니요, 롤리팝에서는 구현 된 기능이 아니라 눈에 띄는 버그 수정이었습니다. 그리고 그것에 대한 심각한 버그.
— 아드리안 Sicaru

젠장, 좋은 테마 솔루션이 있다고 생각했습니다. 이제 돌아가서 버튼 선택기 드로어 블을 만들어야합니다.
— filthy_wizard

4

롤리팝 이전 기기의 드로어 블에서 스타일 속성을 참조 할 수는 없지만 색상 상태 목록은 가능합니다. Android 지원 라이브러리에서 AppCompatResources.getColorStateList (Context context, int resId) 메서드를 사용할 수 있습니다 . 단점은 이러한 색상 상태 목록을 프로그래밍 방식으로 설정해야한다는 것입니다.

다음은 매우 기본적인 예입니다.

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>

색상 상태 목록이 필요한 위젯 :

<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 지원 라이브러리가 Android의 이전 버전 (사전 롤리팝)에서 작동하도록하는 것입니다.

안타깝게도 유사한 드로어 블 메서드 는 스타일 속성과 함께 작동하지 않습니다.


1

https://stackoverflow.com/a/59467269/3841352 에서 동일한 질문에 답변 했지만 여기에도 게시하겠습니다.

동일한 문제가 발생했으며 2019 년에는 해결되지 않았으므로 선택기에서 드로어 블로 참조되는 속성을 가질 수 없습니다. 여기에 게시되지 않았으므로 문제에 대해 얻은 해결책을 공유하겠습니다. 버그 리포트 의 마지막 코멘트에서 발견했습니다 .

해결 방법은 기본적으로 속성 값을 참조하는 드로어 블 리소스를 만드는 것입니다.

귀하의 사례를 설명하기 위해 솔루션은 다음과 같습니다.

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

드로어 블은 다음과 같이 정의됩니다.

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 인 앱에서 계속 사용할 수 있습니다.

AppCompatImageViewv7의 안드로이드 지원 라이브러리는이 기능의 버그 무료 구현을 가지고있다. 간단하게 당신의 용도를 교체 ImageView와 함께 AppCompatImageView.


2
희망찬 소리! 그러나 문제는보기가 아닌 Drawable 모양에 있습니다. 테마 색상을 얻기 위해 attr을 사용하는 모양을 (배경으로) 참조하는 appcompat 뷰가 있으며 <21에서 위의 오류가 발생합니다. 내가 놓친 appcompat 드로어 블이 있습니까?
— NeilS

Android 5.0.1 jy Huawei는 여전히 영향을받습니다.
— southerton
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.