Drawable家族的前世今生

一直都覺得實(shí)現(xiàn)一個(gè)精致的界面或者動(dòng)畫是一件比較費(fèi)時(shí)費(fèi)力的事。最近正好在研究Drawable這個(gè)類辨图,發(fā)現(xiàn)很多效果都可以通過它來實(shí)現(xiàn)故河。但是Drawable家族紛繁復(fù)雜鱼的,不過也正是因?yàn)槿绱硕幻海覀儾趴梢灾苯油ㄟ^Drawable的子類來實(shí)現(xiàn)各種效果衷快。本篇博客主要記錄了如何使用Drawable的子類,來實(shí)現(xiàn)各種效果师郑。

Google對(duì)Drawable的定義是一種可以被繪制在屏幕上的資源呕乎,可以通過代碼或者XML文件來實(shí)現(xiàn)猬仁。
詳細(xì)可見:Android Developer

Drawable的子類很多,通過Android Studio中的繼承視圖可以看到的烁,包括如下:


Drawable

LayerDrawable

LayerDrawable是一組Drawable集合形成的層疊視圖渴庆,它們按照數(shù)組的順序排列襟雷,因此數(shù)組最后的Drawable元素在最上層耸弄。LayerDrawable在XML文件中定義在layer-list標(biāo)簽中卓缰,標(biāo)簽中的每一個(gè)item構(gòu)成它的一個(gè)子Drawable征唬。

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:bottom="50dp"
        android:left="25dp"
        android:right="25dp">
        <shape>
            <solid android:color="#ff0000" />
            <corners android:radius="50dp" />
            <size
                android:width="100dp"
                android:height="100dp" />
        </shape>
    </item>
    <item
        android:top="50dp"
        android:right="50dp">
        <shape>
            <solid android:color="#00ff00" />
            <corners android:radius="50dp" />
            <size
                android:width="100dp"
                android:height="100dp" />
        </shape>
    </item>
    <item
        android:top="50dp"
        android:left="50dp">
        <shape>
            <solid android:color="#0000ff" />
            <corners android:radius="50dp" />
            <size
                android:width="100dp"
                android:height="100dp" />
        </shape>
    </item>
</layer-list>

TransitionDrawable

TransitionDrawable繼承自LayerDrawable扶歪,因此可以知道偿乖,TransitionDrawable實(shí)質(zhì)上也是一種層疊式的視圖資源贪薪,不過它能在第一層和第二層之間實(shí)現(xiàn)漸變式過度画切。TransitionDrawable在XML文件中定義在transition標(biāo)簽中。

<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <solid android:color="#ff0000" />
            <corners android:radius="50dp" />
            <size
            android:width="100dp"
            android:height="100dp" />
        </shape>
    </item>
    <item>
        <shape>
            <solid android:color="#00ff00" />
            <corners android:radius="50dp" />
            <size
            android:width="100dp"
            android:height="100dp" />
        </shape>
    </item>
</transition>

TransitionDrawable只是引用了XML文件還不能生效娃弓,需要在代碼中調(diào)用

TransitionDrawable transitionDrawable = (TransitionDrawable) img.getDrawable();
if (transitionDrawable != null) {
    transitionDrawable.startTransition(5000);
}

RippleDrawable

RippleDrawable也是繼承自LayerDrawable岛宦,Android5.0為點(diǎn)擊控件引入這種水波紋的視圖效果砾肺。RippleDrawable總得說來有5種水波紋效果变汪。
1.沒有邊界的RippleDrawable
要實(shí)現(xiàn)這種效果自需要在ripple標(biāo)簽中指定color就行了

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#ff0000">
</ripple>

2.用顏色作為mask的RippleDrawable
額外的為ripple指定一個(gè)mask顏色

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#ff0000">
    <item android:id="@android:id/mask"
        android:drawable="@android:color/white"/>
</ripple>

3.用圖片作為mask的RippleDrawable
使用圖片作為遮罩時(shí)裙盾,水波紋的擴(kuò)散效果會(huì)限定在圖片的大小范圍呢

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#ff0000">
    <item android:id="@android:id/mask"
        android:drawable="@drawable/shaojiu"/>
</ripple>

4.使用形狀作為mask的RippleDrawable
使用形狀作為遮罩時(shí)番官,水波紋的擴(kuò)散效果會(huì)限定在形狀之內(nèi)。這里使用的形狀其實(shí)也是Drawable的子類假褪,后面也會(huì)介紹到。

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#ff0000">
    <item android:id="@android:id/mask"
        android:drawable="@drawable/ripple_shape"/>
</ripple>

形狀的定義如下:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="#ff0000"/>
    <corners android:radius="100dp"/>
</shape>

5.搭配selector作為RippleDrawable
selector和RippleDrawable一起使用時(shí)宁否,可以在產(chǎn)生水波紋效果的同時(shí)窒升,控件依然能按照selector來顯示不同狀態(tài)下所對(duì)應(yīng)的圖片

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#FF0000" >
    <item>
        <selector>
            <item
                android:drawable="@drawable/kezi2"
                android:state_pressed="true">
            </item>
            <item
                android:drawable="@drawable/kezi1"
                android:state_pressed="false">
            </item>
        </selector>
    </item>
</ripple>

StateListDrawable

StateListDrawable在日常開發(fā)中使用的非常多,不過我們可能并未意識(shí)到慕匠,因?yàn)樗话愣际且陨衔闹兴褂玫降膕elector的形式來使用的饱须。其實(shí)從命名上就可以看出來,StateListDrawable應(yīng)該是包含了一組含有state的drawable數(shù)組台谊。StateListDrawable在XML文件由selector包圍蓉媳。一種最簡單的寫法如下,關(guān)于一個(gè)按鈕的3種狀態(tài)锅铅。

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true"
        android:state_window_focused="true"
        android:drawable="@android:color/holo_red_light"/>
    <item android:state_pressed="true"
        android:state_window_focused="false"
        android:drawable="@android:color/holo_green_light"/>
    <item android:drawable="@android:color/holo_blue_light"/>
</selector>

LevelDrawable

LevelDrawable管理著一組有序的Drawable,每一個(gè)Drawable都有一個(gè)對(duì)應(yīng)"level"盐须,使用的時(shí)候可用通過這個(gè)"level"來選擇對(duì)應(yīng)的Drawable玩荠。通過LevelDrawable可以實(shí)現(xiàn)一組Drawable之內(nèi)的切換,Android系統(tǒng)中有很多的圖標(biāo)效果都是通過它來實(shí)現(xiàn)的,例如:wifi阶冈、移動(dòng)信號(hào)闷尿、電量等。LevelDrawable在XML文件中包含在level-list標(biāo)簽中女坑。

<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:maxLevel="0" android:drawable="@drawable/ic_lv0_large"/>
    <item android:maxLevel="1" android:drawable="@drawable/ic_lv1_large"/>
    <item android:maxLevel="2" android:drawable="@drawable/ic_lv2_large"/>
    <item android:maxLevel="3" android:drawable="@drawable/ic_lv3_large"/>
    <item android:maxLevel="4" android:drawable="@drawable/ic_lv4_large"/>
    <item android:maxLevel="5" android:drawable="@drawable/ic_lv5_large"/>
    <item android:maxLevel="6" android:drawable="@drawable/ic_lv6_large"/>
    <item android:maxLevel="7" android:drawable="@drawable/ic_lv7_large"/>
    <item android:maxLevel="8" android:drawable="@drawable/ic_lv8_large"/>
    <item android:maxLevel="9" android:drawable="@drawable/ic_lv9_large"/>
</level-list>

在代碼中通過設(shè)置LevelDrawable的level就可以顯示對(duì)應(yīng)的視圖層填具,以下代碼通過Handler來實(shí)現(xiàn)了一個(gè)動(dòng)畫效果

private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        drawable.setLevel(index++);
        if (index > 9) {
            index = 0;
        }
        sendEmptyMessageDelayed(0, 700);
    }
};

AnimationDrawable

其實(shí)AnimationDrawable和LevelDrawable很像,AnimationDrawable也管理著一組有序的Drawable匆骗,不過與每個(gè)Drawable對(duì)應(yīng)的不再是level灌旧,而是duration。duration決定了Drawable的存在時(shí)間绰筛,所有的Drawable依次切換便形成了一幀一幀的動(dòng)畫枢泰。AnimationDrawable在XML文件中包含在animation-list標(biāo)簽中。

<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:duration="700" android:drawable="@drawable/ic_lv0_large"/>
    <item android:duration="700" android:drawable="@drawable/ic_lv1_large"/>
    <item android:duration="700" android:drawable="@drawable/ic_lv2_large"/>
    <item android:duration="700" android:drawable="@drawable/ic_lv3_large"/>
    <item android:duration="700" android:drawable="@drawable/ic_lv4_large"/>
    <item android:duration="700" android:drawable="@drawable/ic_lv5_large"/>
    <item android:duration="700" android:drawable="@drawable/ic_lv6_large"/>
    <item android:duration="700" android:drawable="@drawable/ic_lv7_large"/>
    <item android:duration="700" android:drawable="@drawable/ic_lv8_large"/>
    <item android:duration="700" android:drawable="@drawable/ic_lv9_large"/>
</animation-list>

AnimationDrawable不會(huì)自動(dòng)播放铝噩,需要在代碼中手動(dòng)調(diào)用start

ImageView animationImg = (ImageView) findViewById(R.id.animation_img);
AnimationDrawable drawable = (AnimationDrawable) animationImg.getDrawable();
drawable.start();

ShapeDrawable

ShapeDrawable支持4種形狀衡蚂,line、oval骏庸、rectangle毛甲、ring。在XML文件中包含在shape標(biāo)簽哦中具被。

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <size
        android:width="200dp"
        android:height="200dp" />
    <corners android:radius="100dp" />
    <gradient
        android:angle="0"
        android:type="linear"
        android:endColor="#00ff00"
        android:startColor="#ff0000" />
    <stroke
        android:width="2dp"
        android:color="#0000ff"
        android:dashGap="10dp"
        android:dashWidth="10dp" />
</shape>

DrawableWrapper

顧名思義玻募,Drawable包裹器。DrawableWrapper只能包含一個(gè)Drawable一姿,可以通過繼承DrawableWrapper來實(shí)現(xiàn)對(duì)包裹的Drawable的一些特殊處理七咧。Android官方已經(jīng)提供了4個(gè)常用的包裹器,InsetDrawable叮叹、ClipDrawable艾栋、ScaleDrawable、RotateDrawable蛉顽。

1.InsertDrawable

<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/shaojiu"
    android:inset="20dp">
</inset>

2.ClipDrawable

<clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/shaojiu"
    android:gravity="center"
    android:clipOrientation="horizontal">
</clip>

3.ScaleDrawable

<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/shaojiu"
    android:scaleGravity="center"
    android:scaleWidth="50%"
    android:scaleHeight="50%">
</scale>

4.RotateDrawable

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/shaojiu"
    android:pivotX="50%"
    android:pivotY="50%"
    android:fromDegrees="45"
    android:toDegrees="0">
</rotate>

VectorDrawable

VectorDrawable是通過XML定義的矢量視圖蝗砾,它有很多好處。首先携冤,因?yàn)樗荴ML文件悼粮,使用它能縮減apk的體積,第二曾棕,因?yàn)槭鞘噶课募勖ǎ栽诓煌峙渎实氖謾C(jī)上顯示的時(shí)候不會(huì)出現(xiàn)模糊。VectorDrawable在XML文件中包含在vector標(biāo)簽中睁蕾,在Android Studio中可以通過導(dǎo)入svg文件來生成苞笨。svg圖形主要是通過一系列的路徑構(gòu)成的债朵,可以通過PS之類的工具來生成。
一個(gè)簡單的VectorDrawable文件如下:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="64dp"
    android:height="64dp"
    android:viewportWidth="600"
    android:viewportHeight="600">
    <path
        android:name="angel"
        android:fillColor="#ff0000"
        android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z"/>
</vector>

VectorDrawable還可以通過AnimationVectorDrawable形成矢量動(dòng)畫瀑凝。AnimationVectorDrawable需有三個(gè)XML文件序芦,包含animated-vector標(biāo)簽的XML文件、執(zhí)行動(dòng)畫的XML文件粤咪、和上文所提到的矢量圖形文件谚中。
drawable/animated-vector

<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_vector_angel">
    <target
        android:animation="@anim/path"
        android:name="angel" />
</animated-vector>

animator/path

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:duration="3000"
        android:propertyName="pathData"
        android:valueFrom="M300,70 l 0,-70 70,70 0,0 -70,70z"
        android:valueTo="M300,70 l 0,-70 70,0  0,140 -70,0 z"
        android:valueType="pathType" />
</set>

drawable/ic_vector_angle

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="64dp"
    android:height="64dp"
    android:viewportWidth="600"
    android:viewportHeight="600">
    <path
        android:name="angle"
        android:fillColor="#ff0000"
    android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z"/>
</vector>

同樣,矢量動(dòng)畫要?jiǎng)悠饋砹戎Γ彩切枰诖a中手動(dòng)start宪塔。

ImageView vectorImg = (ImageView) findViewById(R.id.vector_img);
AnimatedVectorDrawable drawable = (AnimatedVectorDrawable) vectorImg.getDrawable();
drawable.start();

DrawerArrowDrawable

DrawerArrowDrawable是一個(gè)包含動(dòng)畫的矢量視圖,它可以配合DrawerLayout一起使用囊拜。使用起來也很簡單某筐,在滑入滑出側(cè)邊欄的時(shí)候不斷修改DrawerArrowDrawable就可以了。

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <RelativeLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="向右滑動(dòng)拉出菜單"/>
    </RelativeLayout>
    <LinearLayout
        android:layout_width="280dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#fafafa"
        android:orientation="vertical">
        <ListView
            android:id="@+id/drawer_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>
</android.support.v4.widget.DrawerLayout>

代碼中動(dòng)態(tài)修改DrawerArrowDrawable

drawerLayout.setDrawerListener(new DrawerLayout.SimpleDrawerListener() {
    @Override
    public void onDrawerSlide(View drawerView, float slideOffset) {
        super.onDrawerSlide(drawerView, slideOffset);
        drawable.setProgress(slideOffset);
    }
});

其他類型的Drawable

Drawable中還有一些子類冠跷,比較簡單南誊,只包含一個(gè)Drawable。ColorDrawable蜜托、PictureDrawable抄囚、BitmapDrawable、NinePatchDrawable橄务。具體的使用可以參考Android官方的例子幔托。

Drawable家族實(shí)際上蠻復(fù)雜的,因?yàn)樗膬?nèi)容比較多蜂挪。以前老是在實(shí)現(xiàn)某種效果的時(shí)候忘了該用哪種Drawable重挑,因此在這篇博客中完整的總結(jié)一下。嘛锅劝!內(nèi)容太多攒驰,都只是介紹一下最簡單的使用方法(難了也不會(huì)啊>_<)。該博客的Demo也上傳到github上面啦故爵!歡迎大家Star~~~

首次的技術(shù)文章,總算是完成啦隅津!完結(jié)散花...

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末诬垂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子伦仍,更是在濱河造成了極大的恐慌结窘,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件充蓝,死亡現(xiàn)場離奇詭異隧枫,居然都是意外死亡喉磁,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門官脓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來协怒,“玉大人,你說我怎么就攤上這事卑笨≡邢荆” “怎么了?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵赤兴,是天一觀的道長妖滔。 經(jīng)常有香客問我,道長桶良,這世上最難降的妖魔是什么座舍? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮陨帆,結(jié)果婚禮上簸州,老公的妹妹穿的比我還像新娘。我一直安慰自己歧譬,他們只是感情好岸浑,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瑰步,像睡著了一般矢洲。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上缩焦,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天读虏,我揣著相機(jī)與錄音,去河邊找鬼袁滥。 笑死盖桥,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的题翻。 我是一名探鬼主播揩徊,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼嵌赠!你這毒婦竟也來了塑荒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤姜挺,失蹤者是張志新(化名)和其女友劉穎齿税,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體炊豪,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡凌箕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年拧篮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片牵舱。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡串绩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出仆葡,到底是詐尸還是另有隱情赏参,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布沿盅,位于F島的核電站把篓,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏腰涧。R本人自食惡果不足惜韧掩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望窖铡。 院中可真熱鬧疗锐,春花似錦、人聲如沸费彼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽箍铲。三九已至雇卷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間颠猴,已是汗流浹背关划。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留翘瓮,地道東北人贮折。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像资盅,于是被迫代替她去往敵國和親调榄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容