前言
不知道你們有沒(méi)有遇到這樣一種場(chǎng)景:
設(shè)計(jì)師:“首頁(yè)這個(gè)按鈕圓角度數(shù)為5個(gè)像素”
你:“OK”疮方,言語(yǔ)間你已經(jīng)在drawable目錄下創(chuàng)建了一個(gè)xml文件工三,定義了圓角的shape襟齿,然后給Imageview設(shè)置上:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#f1de11"/>
<corners android:radius="5px"/>
</shape>
過(guò)了5分鐘……
設(shè)計(jì)師:頂部的Tab選中時(shí)的背景也給它紅色圓角8像素吧
你:“可以”伍玖。反正舉手之勞悴务,再建個(gè)xml就好了”
過(guò)了一會(huì)兒ui復(fù)審…
設(shè)計(jì)師:“新消息提醒改成小圓形吧”
你內(nèi)心:Orz…再這么建下去…
?
開(kāi)個(gè)玩笑享幽,不過(guò)確實(shí)很多時(shí)候我們的項(xiàng)目中會(huì)存在很多圓角背景的ui铲掐,而且一般都還每個(gè)地方的圓角度數(shù)都略有差別,這種時(shí)候是不是內(nèi)心有一種特別想動(dòng)態(tài)更改xml的屬性的沖動(dòng)(不然每個(gè)都對(duì)應(yīng)一個(gè)文件到時(shí)候豈不是一堆)值桩,既然xml不可以摆霉,何不試一下代碼上動(dòng)態(tài)生成呢?
?
動(dòng)態(tài)實(shí)現(xiàn)圓角背景
我們都知道ImageView可以設(shè)置Drawable奔坟,如果我們動(dòng)態(tài)生成一個(gè)圓角的Drawable豈不美哉携栋,恰好Android中有這么一個(gè)類GradientDrawable,它繼承于Drawable蛀蜜,提供了各種shape標(biāo)簽的屬性設(shè)置接口刻两,轉(zhuǎn)換成對(duì)應(yīng)形態(tài)的Drawable對(duì)象。因此我們可以定義這么一個(gè)方法滴某,只需傳入圓角度數(shù)磅摹、顏色和邊緣寬度滋迈,以及是否填充,即可得到一個(gè)等同于xml效果的Drawable資源對(duì)象:
public static GradientDrawable getRoundRectDrawable(int radius, int color, boolean isFill, int strokeWidth){
//左上户誓、右上饼灿、右下、左下的圓角半徑
float[] radius = {radius, radius, radius, radius, radius, radius, radius, radius};
GradientDrawable drawable = new GradientDrawable();
drawable.setCornerRadii(radius);
drawable.setColor(isFill ? color : Color.TRANSPARENT);
drawable.setStroke(isFill ? 0 : strokeWidth, color);
return drawable;
}
?
使用:
ImageView imageView = findViewById(R.id.image_view);
imageView.setBackground(ShapeUtils.getRoundRectDrawable(40, Color.parseColor("#5bc0de"), true, 10));
?
效果如圖:
就再也不用因?yàn)槟硞€(gè)小屬性的差別而新建那么多的xml文件帝美,既減少了apk的體積碍彭,又便于統(tǒng)一管理和替換,因此可根據(jù)實(shí)際需要可采用動(dòng)態(tài)方式和靜態(tài)方式相結(jié)合悼潭。(此處只是舉例最簡(jiǎn)單的shape例子庇忌,其它屬性設(shè)置可參見(jiàn)API或文末Github地址)
?
動(dòng)態(tài)圖標(biāo)換色
另外一種場(chǎng)景,就是很多app都會(huì)有底部tab用于切換主功能舰褪,當(dāng)前選中的那個(gè)tab的圖標(biāo)肯定和其他未被選中的tab的圖標(biāo)不一樣皆疹,有些是做了一些動(dòng)畫(huà)效果并且對(duì)圖標(biāo)細(xì)節(jié)進(jìn)行了一定調(diào)整,另外一些是圖標(biāo)無(wú)論是否被選中占拍,都是那樣的形狀略就,只是單純換了個(gè)顏色,這種情況我們一般會(huì)讓ui再另外切一套著色了的圖標(biāo)晃酒,然后代碼中動(dòng)態(tài)切換圖標(biāo)表牢,達(dá)到切換tab的效果。但這種方式同樣存在一個(gè)問(wèn)題贝次,兩套一摸一樣的圖標(biāo)崔兴,只是顏色不一樣,這樣會(huì)不會(huì)有點(diǎn)占用apk體積浊闪,是否可以通過(guò)動(dòng)態(tài)給Icon涂上顏色呢恼布?
答案是可以的,同樣是通過(guò)Drawable來(lái)操作搁宾,圖標(biāo)本身可以通過(guò)getDrawable轉(zhuǎn)換為Drawable對(duì)象折汞,然后再通過(guò)DrawCompat來(lái)進(jìn)行重新著色:
/**
* 將drawable顏色著色為color
* @param drawable
* @param color
* @return 重繪后的Drawable
*/
public static Drawable drawColor(Drawable drawable, int color) {
final Drawable wrappedDrawable = DrawableCompat.wrap(drawable);
wrappedDrawable.mutate();
DrawableCompat.setTint(wrappedDrawable, color);
return wrappedDrawable;
}
?
首先DrawableCompat.wrap
是將drawable轉(zhuǎn)換為可著色的Drawable對(duì)象,然后調(diào)用mutate
是表示只對(duì)當(dāng)前這個(gè)對(duì)象進(jìn)行著色盖腿,假如不調(diào)用這句爽待,到時(shí)候一著完色,以后再getDrawable獲取這個(gè)對(duì)象的時(shí)候翩腐,就都變成著色后的了(即拿不到之前原來(lái)的那個(gè)Drawable了)鸟款,然后setTint
就是將我們想要重繪的顏色繪制上去了,最后將新的Drawable返回茂卦,同樣設(shè)置給ImageView何什,就可以變成另外一個(gè)顏色的Icon了。
弄了個(gè)簡(jiǎn)單的動(dòng)畫(huà)等龙,不斷對(duì)icon進(jìn)行染色:
final ImageView imageView = findViewById(R.id.image_view);
ValueAnimator animator = ValueAnimator.ofArgb(Color.parseColor("#3F51B5"),Color.parseColor("#FF4081"));
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int color = (int)animation.getAnimatedValue();
imageView.setBackground(ShapeUtils.drawColor(getResources().getDrawable(R.drawable.ic_android), color));
}
});
?
效果如圖:
?
總結(jié)
這兩種方式有時(shí)候在特別多重復(fù)但卻有略微差別的ui場(chǎng)景中可以派上用場(chǎng)处渣,另外還可以用來(lái)統(tǒng)一控制某些圖標(biāo)的顏色或者多個(gè)圓角的控制伶贰,具體結(jié)合實(shí)際情況進(jìn)行運(yùn)用。
這里只是列舉了幾個(gè)shape的常用屬性罐栈,它還有其他很多屬性可以動(dòng)態(tài)設(shè)置黍衙,把它們封裝成了一個(gè)工具類,代碼已傳到 GitHub-ZJYWidget 荠诬。里面有很多實(shí)用的自定義View源碼及demo琅翻,會(huì)長(zhǎng)期維護(hù),歡迎Star~ 如有不足之處或建議還望指正柑贞,相互進(jìn)步方椎,如果覺(jué)得不錯(cuò)動(dòng)動(dòng)小手給個(gè)喜歡, 謝謝~