Android 5.0以下XML定義的drawable不識別?attr/屬性的解決思路
最近寫個小專案,之前一直使用5.0 和7.0系統的手機測試正常,換到4.4系統卻報Resources$NotFoundException錯誤,很是疑惑,因為錯誤指向的drawable檔案正常啊,把log複製到搜尋引擎查了一下,也沒什麼收穫,但查到有個類似的問題,是:TextView.setText()時,直接給了一個int型的引數,導致系統把這個引數當做Resource id去處理了。 根據這個思路,我開啟我的drawable檔案,試著把裡面的"?attr/colorPrimary"換成“@color/顏色資源”,結果沒有報錯。網上查了一下,果然是5.0以下,在drawable中無法正確引用?attr/的值(我的想法是:系統本應該取到顏色值,可卻把這個值做resource id處理了,然後根據id去尋找資源時,沒有找到資源)。
可因為我在軟體中加入了主題更換的功能,所以要獲取實時的?attr/colorPrimary,而不是固定的color資源,於是想了些解決辦法:
1、新建drawable-21 資料夾,對於5.0和5.0 以下系統的drawable資源分別定義,這樣可以解決,但是分別定義的drawable因為使用的資源的不同可能導致效果不同。
2、邏輯上避開在drawable中引用?attr/資源。比如我在某一個按鈕上的效果:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="96dp"
android:layout_height="40dp"
android:layout_centerInParent="true"
android:background="@drawable/btn_pressed"
android:text="按鈕"
android:textColor="#FFFFFF"/>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false">
<shape android:shape="rectangle">
<solid android:color="?colorPrimary"/>
</shape>
</item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="?colorPrimaryDark"/>
</shape>
</item>
</selector>
很簡單,就不上圖了,96*48的按鈕,觸控時和不觸控時引用不同的顏色。可在5.0 以下系統,肯定會報Resources$NotFoundException,怎麼解決呢?
我們可以在這個按鈕下面放一個同樣大小的控制元件,任何設定該控制元件的background為?colorPrimary。然後在按鈕的drawable檔案中,將不觸控時的顏色設為全透明,觸控時設為一定透明度的黑色。如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="96dp"
android:layout_height="40dp"
android:layout_centerInParent="true"
android:background="?colorPrimary">
<Button
android:layout_width="96dp"
android:layout_height="40dp"
android:background="@drawable/btn_pressed"
android:text="按鈕"
android:textColor="#FFFFFF"/>
</FrameLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false">
<shape android:shape="rectangle">
<!--全透明色-->
<solid android:color="#00000000"/>
</shape>
</item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<!--透明度為12的黑色-->
<solid android:color="#1E000000"/>
</shape>
</item>
</selector>
兩次的效果是差不多的,通過調整透明色,可以達到一樣的效果。這樣,我們避開了在drawable中引用?attr的資源,而且到達預期的效果了。3、在java程式碼中定義drawable。這也是最好的一種解決辦法,我們可以在程式碼中獲取到?attr/資源的值,然後在定義的drawable中引用就行了,
public class TestActivity extends AppCompatActivity{
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
Utils.context=this;
Button button=(Button)findViewById(R.id.btn);
button.setBackground(getStateListDrawable());
}
// 對應drawable 中的selector
private StateListDrawable getStateListDrawable(){
StateListDrawable stateListDrawable=new StateListDrawable();
stateListDrawable.addState(new int[]{-android.R.attr.state_pressed},getGradientDrawable(false));
stateListDrawable.addState(new int[]{android.R.attr.state_pressed},getGradientDrawable(true));
return stateListDrawable;
}
// 對應drawable 中的 shape
private GradientDrawable getGradientDrawable(boolean isPressed){
GradientDrawable gradientDrawable=new GradientDrawable();
gradientDrawable.setShape(GradientDrawable.RECTANGLE);
// 獲取顏色
TypedValue primaryValue=new TypedValue();
TypedValue primaryDarkValue=new TypedValue();
this.getTheme().resolveAttribute(R.attr.colorPrimary,primaryValue,true);
this.getTheme().resolveAttribute(R.attr.colorPrimaryDark,primaryDarkValue,true);
// 背景顏色
if(isPressed){
gradientDrawable.setColor(primaryDarkValue.data);
} else {
gradientDrawable.setColor(primaryValue.data);
}
gradientDrawable.setBounds(0,0,SizeUtils.dp2px(96),SizeUtils.dp2px(48));
return gradientDrawable;
}
}
程式碼很簡單,可以對應在xml中定義drawable的方式來看,實現的效果和之前的一樣。關於上面用到的StateListDrawable
GradientDrawable
兩個類,大家可以去詳細學習一下,我這裡知識提一下解決思路,如果你有更好的方法,可以在下面評論告訴我。
還是上傳個圖片吧,上面實現的效果:
相關文章
- Android中View自定義XML屬性詳解以及R.attr與R.styleable的區別AndroidViewXML
- 定義物料型別的屬性型別
- Android XML 屬性AndroidXML
- Windows安裝時不識別硬碟(儲存器)的解決思路.Windows硬碟
- Drawable一個有趣的屬性 tileMode
- android中自定義屬性重複定義Android
- Android 自定義 DrawableAndroid
- 給自定義View新增xml屬性ViewXML
- XML中的DTD文件型別定義XML型別
- Laravel ORM Model 的預定義屬性LaravelORM
- XML Schema(XSD)詳解:定義 XML 文件結構合法性的完整指南XML
- Hibernate 對映xml中的屬性型別XML型別
- Android自定義屬性Android
- Android--系統不識別adb命令的解決辦法Android
- Xamarin Android提示找不到資源屬性定義Android
- XML屬性XML
- Android開發-TextViev XML屬性(一)AndroidXML
- 初識css自定義屬性CSS
- Android 的各種 Drawable 詳解Android
- Android 深入理解Android中的自定義屬性Android
- SAP MM 定義物料型別的屬性配置裡的New entries按鈕型別
- Android – Drawable 詳解Android
- XML 屬性概述XML
- [android]智慧遍歷的解決思路Android
- XMl 檔案屬性的讀取XML
- Android通過XML來定義MenuAndroidXML
- Android自定義View 屬性新增AndroidView
- MQTT 5.0 連線屬性MQQT
- FeignClient註解屬性configuration不生效問題排查思路client
- Android中RelativeLayout各個屬性的含義Android
- ts類中屬性定義的另一種方式
- jsp頁面不能識別bean的屬性JSBean
- Android自定義控制元件——自定義屬性Android控制元件
- Android鬼點子 自定義控制元件印上LOGO的解決思路Android控制元件Go
- Android屬性設定android:noHistory="true"Android
- Android中 @和?區別以及?attr/**與@style/**等的區別Android
- Android activity屬性設定大全Android
- XML Schema 複雜元素型別詳解:定義及示例解析XML型別