最近寫個小項目煞茫,之前一直使用5.0 和7.0系統(tǒng)的手機測試正常,換到4.4系統(tǒng)卻報Resources$NotFoundException錯誤摄凡,很是疑惑续徽,因為錯誤指向的drawable文件正常啊,把log復制到搜索引擎查了一下亲澡,也沒什么收獲钦扭,但查到有個類似的問題,是:TextView.setText()時床绪,直接給了一個int型的參數(shù)客情,導致系統(tǒng)把這個參數(shù)當做Resource id去處理了其弊。 根據這個思路,我打開我的drawable文件膀斋,試著把里面的"?attr/colorPrimary"換成“@color/顏色資源”梭伐,結果沒有報錯。網上查了一下仰担,果然是5.0以下糊识,在drawable中無法正確引用?attr/的值(我的想法是:系統(tǒng)本應該取到顏色值摔蓝,可卻把這個值做resource id處理了赂苗,然后根據id去尋找資源時,沒有找到資源)项鬼。
可因為我在軟件中加入了主題更換的功能哑梳,所以要獲取實時的?attr/colorPrimary,而不是固定的color資源绘盟,于是想了些解決辦法:
1鸠真、新建drawable-21 文件夾,對于5.0和5.0 以下系統(tǒng)的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 以下系統(tǒng)搞坝,肯定會報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的方式來看张抄,實現(xiàn)的效果和之前的一樣。關于上面用到的StateListDrawableGradientDrawable
兩個類洼怔,大家可以去詳細學習一下署惯,我這里知識提一下解決思路,如果你有更好的方法镣隶,可以在下面評論告訴我.....還是上傳個圖片吧极谊,上面實現(xiàn)的效果: