一直都覺得實(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中的繼承視圖可以看到的烁,包括如下:
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é)散花...