Android 動(dòng)態(tài)實(shí)現(xiàn)圓角背景和圖標(biāo)換色小技巧

前言

不知道你們有沒(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));

?
效果如圖:


動(dòng)態(tài)生成圓角圖

就再也不用因?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)畫效果并且對(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)畫,不斷對(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));
            }
});

?
效果如圖:


圖標(biāo)染色

?

總結(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è)喜歡, 謝謝~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • ¥開(kāi)啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開(kāi)一個(gè)線程,因...
    小菜c閱讀 7,294評(píng)論 0 17
  • 概述 今天我們來(lái)探究一下android的樣式。其實(shí),幾乎所有的控件都可以使用 background屬性去引用自定義...
    CokeNello閱讀 5,087評(píng)論 1 19
  • 很早看過(guò)這篇文章,并做了筆記,后來(lái)看到群里的小伙伴有問(wèn)相關(guān)Drawable的問(wèn)題,就把這篇翻譯過(guò)來(lái)的文章給放出來(lái)了...
    Kotyo閱讀 1,676評(píng)論 0 5
  • 一、前言 在 Android 的開(kāi)發(fā)過(guò)程中,Drawable 經(jīng)常會(huì)被用到,一般會(huì)用 Drawable 為 Vie...
    承香墨影閱讀 1,016評(píng)論 1 16
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,029評(píng)論 4 61

友情鏈接更多精彩內(nèi)容