轉載自 :
https://blog.csdn.net/linghu_java/article/details/42119969
Android把可繪制的對象抽象為Drawable,不同的圖形圖像資源就代表着不同的drawable類型。Android FrameWork提供了一些具體的Drawable實作,通常在代碼中都不會直接接觸Drawable的實作類。
在實際的開發過程中,會把使用到的資源都放置在res/drawable目錄,剩下的工作交給Android SDK 就行了,當需要使用圖檔資源的時候,可以使用@drawable标志在xml中引用drawable資源就行,也可以在代碼中使用id引用這些drawable資源.
在使用drawable資源的時,有一點需要注意,drawable預設是記憶體共享的,也就說在不同的地方使用了同一個drawable,它們都指向相同的資源,而且具有相同的狀态,如果在一個地方修改了這個drawable,所有使用它的地方都會改變。
Android内置了如下幾種Drawable類型:ColorDrawable、GradientDrawable、BitmapDrawable、 NinePatchDrawable、InsetDrawable、ClipDrawable、ScaleDrawable、RotateDrawable、AnimationDrawable、LayerDrawable、LevelListDrawable、StateListDrawable、TransitionDrawable.
除了這些預置的drawable實作類以外,也可以自定義drawable的實作類型,大部分情況都不需要自定義drawable類型,使用系統提供的這些drawable實作類型已經覆寫了很多情況。在實際的程式設計過程中也很少會接觸這些具體drawable實作類型,因為編寫android應用程式使用xml可以很容易的建立drawable,隻有在程式中需要修改drawable的屬性時,才需要使用具體的drawable類型提供的方法來處理。下面就來逐個認識這些Drawable類型。
一、ColorDrawable
ColorDrawable 是最簡單的Drawable,它實際上是代表了單色可繪制區域,它包裝了一種固定的顔色,當ColorDrawable被繪制到畫布的時候會使用顔色填充Paint,在畫布上繪制一塊單色的區域。
在xml檔案中使用color作為根節點來建立ColorDrawable,它隻有一個android:color屬性,通過它來決定ColorDrawable的顔色,Android并沒有提供修改這個顔色值的Api,是以這個顔色一旦設定之後,就不能直接修改了。
下面的xml檔案定義了一個顔色為紅色的ColorDrawable:
[代碼]xml代碼:
<?xml version="1.0" encoding="utf-8"?>
<color
xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#ff0000">
</color>
當然也可以使用Java代碼建立ColorDrawable,需要注意的是Android中使用一個int類型的資料表示顔色值,通常習慣使用十六進制格式的資料表示顔色值。一個int類型包含四個位元組,分别代表顔色的4個組成部分:透明度(Alpha)、紅(RED)、綠(GREEN)、藍(BLUE),每個部分由一個位元組(8個bit)表示,取值範圍為0~255。在xml中使用顔色時可以省略透明度(Alpha)部分,如#ff0000表示紅色。但是在代碼中必須要明确指出透明度(Alpha)代表的資料,如果省略了就表示完全透明的顔色,例如0xFFFF0000表示紅色,而0xFF0000雖然也表示紅色,但它卻是完全透明的,也就是說當繪制到畫布上時,看不出有任何效果.
使用Java代碼也可以建立ColorDrawable,代碼如下:
[代碼]java代碼:
ColorDrawable drawable =
new
ColorDrawable(
0xffff0000
);
二、GradientDrawable
GradientDrawable 表示一個漸變區域,可以實作線性漸變、發散漸變和平鋪漸變效果,在Android中可以使用GradientDrawable表示很多複雜而又絢麗的界面效果。
可以使用xml定義GradientDrawable,相對于ColorDrawable類型,GradientDrawable要複雜很多,它有很多的元素組成。在xml檔案中使用shape作為根節點來建立GradientDrawable,它包含很多屬性和子節點,下面是GradientDrawable的xml文檔節點結構。
[代碼]xml代碼:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<size/>// 定義區域的大小
<gradient/>//設定區域背景的漸變效果
<solid/> //設定區域的背景顔色,如果設定了solid會覆寫gradient的效果
<stroke/> //設定區域的邊框效果
<padding/> //設定區域的内邊距
</shape>
在我們實際操作shape的時候我們需要先了解shape的各種屬性的作用:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape=["rectangle" | "oval" | "line" | "ring"] //共有4種類型,矩形(預設)/橢圓形/直線形/環形
// 以下4個屬性隻有當類型為環形時才有效
android:innerRadius="dimension" //内環半徑
android:innerRadiusRatio="float" //内環半徑相對于環的寬度的比例,比如環的寬度為50,比例為2.5,那麼内環半徑為20
android:thickness="dimension" //環的厚度
android:thicknessRatio="float" //環的厚度相對于環的寬度的比例
android:useLevel="boolean"> //如果當做是LevelListDrawable使用時值為true,否則為false.
<corners //定義圓角
android:radius="dimension" //全部的圓角半徑
android:topLeftRadius="dimension" //左上角的圓角半徑
android:topRightRadius="dimension" //右上角的圓角半徑
android:bottomLeftRadius="dimension" //左下角的圓角半徑
android:bottomRightRadius="dimension" /> //右下角的圓角半徑
<gradient //定義漸變效果
android:type=["linear" | "radial" | "sweep"] //共有3中漸變類型,線性漸變(預設)/放射漸變/掃描式漸變
android:angle="integer" //漸變角度,必須為45的倍數,0為從左到右,90為從上到下
android:centerX="float" //漸變中心X的相當位置,範圍為0~1
android:centerY="float" //漸變中心Y的相當位置,範圍為0~1
android:startColor="color" //漸變開始點的顔色
android:centerColor="color" //漸變中間點的顔色,在開始與結束點之間
android:endColor="color" //漸變結束點的顔色
android:gradientRadius="float" //漸變的半徑,隻有當漸變類型為radial時才能使用
android:useLevel=["true" | "false"] /> //使用LevelListDrawable時就要設定為true。設為false時才有漸變效果
<padding //内部邊距
android:left="dimension"
android:top="dimension"
android:right="dimension"
android:bottom="dimension" />
<size //自定義的圖形大小
android:width="dimension"
android:height="dimension" />
<solid //内部填充顔色
android:color="color" />
<stroke //描邊
android:width="dimension" //描邊的寬度
android:color="color" //描邊的顔色
// 以下兩個屬性設定虛線
android:dashWidth="dimension" //虛線的寬度,值為0時是實線
android:dashGap="dimension" /> //虛線的間隔
</shape>
以下是幾種不同漸變效果實作的xml檔案代碼:
<?xml version="1.0" encoding="utf-8"?>
<!--線性漸變的橢圓-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<gradient
android:type="linear"
android:angle="90"
android:gradientRadius="200dp"
android:startColor="#e61010"
android:centerColor="#38df0e"
android:endColor="#d7da08"/>
<stroke
android:color="#ffffff"
android:width="3dp"
android:dashGap="5dp"
android:dashWidth="5dp"/>
</shape>
<?xml version="1.0" encoding="utf-8"?>
<!--平鋪漸變的圓環-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="ring"
android:innerRadiusRatio="8"
android:thicknessRatio="3"
android:useLevel="false"
>
<gradient
android:type="sweep"
android:useLevel="false"
android:gradientRadius="200dp"
android:startColor="#e61010"
android:centerColor="#38df0e"
android:endColor="#d7da08"/>
</shape>
<?xml version="1.0" encoding="utf-8"?>
<!--發散漸變效果的圓-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="ring"
android:innerRadius="0dp"
android:thickness="70dp"
android:useLevel="false"
>
<gradient
android:type="radial"
android:useLevel="false"
android:gradientRadius="50dp"
android:startColor="#e61010"
android:centerColor="#38df0e"
android:endColor="#d7da08"/>
</shape>
三、BitmapDrawable
BitmapDrawable 是對bitmap的一種包裝,可以設定它包裝的bitmap在BitmapDrawable區域内的繪制方式,如平鋪填充、拉伸填充或者保持圖檔原始大小,也可以在BitmapDrawable區域内部使用gravity指定的對齊方式。
在xml檔案中使用bitmap作為根節點來定義BitmapDrawable。
下面的xml代碼定義一個BitmapDrawable,同時設定了BitmapDrawable的tileMode 屬性為repeat,通過這樣設定會使用小圖檔在水準和豎直方向做鏡面平鋪效果。
[代碼]xml代碼
<?xml version="1.0" encoding="utf-8"?>
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/ic_person"
android:antialias="true"
android:dither="true"
android:filter="true"
android:mipMap="false"
android:gravity="center"
android:tileMode="repeat">
</bitmap>
原圖:
效果圖:
Bitmap的屬性:
gravity屬性詳情:
也可以使用Java代碼實作相同的效果,等價的Java代碼如下:
Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_person);
BitmapDrawable mBitmapDrawable = new BitmapDrawable(mBitmap);
mBitmapDrawable.setTileModeXY(TileMode.MIRROR, TileMode.MIRROR);
mBitmapDrawable.setAntiAlias(true);
mBitmapDrawable.setDither(true);
mDrawable = mBitmapDrawable;
四、NinePatchDrawable (點九圖)
NinePatchDrawable,“點九圖”是Andriod平台的一種特殊的圖檔格式,檔案擴充名為:.9.png。支援Android平台的手機類型很多,有多種不同的分辨率,很多控件的切圖檔案在被放大拉伸後,邊角會模糊失真。在android平台下使用“點九”圖檔處理技術,可以将圖檔橫向和縱向同時進行拉伸,以實作在多分辨率下的完美顯示效果。點九圖檔在拉伸時仍能保留圖像的漸變質感和圓角的精細度。
Android SDK工具集提供了處理點九圖檔的工具,可以通過draw9patch.bat運作,通過這個工具可以很容易把普通的PNG圖檔處理成“點九”圖檔。從它的名字也很容易了解“點九”圖的含義,其實相當于把一張PNG圖分成了9個部分(九宮格),分别為4個角,4條邊,以及一個中間區域,4個角是不做拉伸的,是以還能一直保持圓角的清晰狀态,而2條水準邊和2條垂直邊分别隻做水準和垂直拉伸,是以不會出現邊框被拉粗的情況,隻有中間用黑線指定的區域做拉伸,通過這種處理方式圖檔才不會失真。
自己生成 .9圖:ic_launcher.9.png
使用了*.9.png圖檔技術後,隻需要采用一套界面切圖去适配不同的分辨率,而且大幅減少安裝包的大小。Android FrameWork在顯示點九圖檔時使用了高效的優化算法,所示應用程式不需要專門做處理就可以實作圖檔拉伸自适應,減少了代碼量和實際開發的工作量。
在xml檔案中使用使用nine-patch作為根節點建立NinePatchDrawable。同時,也可以使用bitmap包裝點九圖檔,android FrameWork會根據android:src屬性設定的圖檔類型來生成對應的drawable。代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<nine-patch
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/ic_launcher"
android:dither="true">
</nine-patch>
下面看一下原始點九圖檔以及拉伸之後的效果:
最後,需要指出的是,Android雖然可以使用Java代碼建立NinePatchDrawable,但是極少情況會那麼做,主要的原因是由于Android SDK會在編譯工程時對點九圖檔進行編譯,形成特殊格式的圖檔。使用代碼建立NinePatchDrawable時隻能針對編譯過的點九圖檔資源,對于沒有編譯過的點九圖檔資源都當做BitmapDrawable對待。在使用點九圖檔時需要注意的是,點九圖隻能适用于拉伸的情況,對于壓縮的情況并不适用,如果需要适配很多分辨率的螢幕時需要把點九圖做的小一點。
五、InsetDrawable
InsetDrawable 表示一個drawable嵌入到另外一個drawable内部,并且在内部留一些間距,這一點很像drawable的padding屬性,差別在于 padding表示drawable的内容與drawable本身的邊距,insetDrawable表示兩個drawable和容器之間的邊距。當控件需要的背景比實際的邊框小的時候比較适合使用InsetDrawable。
總結一下:
- 對應
标簽inset
- 将其他Drawable内嵌到自身,并在四周留出間距
- View需要背景比自己實際區域要小的時候,可以使用
,inset
也可以實作該需求layer-list
下面的xml定義了一個四邊邊距都為20dip的InsetDrawable,代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/icon_fengjng"
android:insetLeft="20dp"
android:insetRight="20dp"
android:insetTop="20dp"
android:insetBottom="20dp">
</inset>
效果圖:上邊是引入insetdrawable,下邊是原圖:空白部分可以看出效果
<Button
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="@drawable/inset_drawable"
android:text="button"/>
<Button
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="@drawable/icon_fengjng"
android:text="button"/>
六、ClipDrawable
ClipDrawable 是對一個Drawable進行剪切操作,可以控制這個drawable的剪切區域,以及相相對于容器的對齊方式,android中的進度條就是使用一個ClipDrawable實作效果的,它根據level的屬性值,決定剪切區域的大小。
在xml檔案中使用clip作為根節點定義ClipDrawable。
需要注意的是ClipDrawable是根據level的大小控制圖檔剪切操作的,官方文檔的note中提到:The drawable is clipped completely and not visible when the level is 0 and fully revealed when the level is 10,000。也就是level的大小從0到10000,level為0時完全不顯示,為10000時完全顯示。是用Drawable提供的setLevel(int level)方法來設定剪切區域。
方向:android:clipOrientation="vertical|horizontal"
android:gravity="left|right|top|bottom|center"
xml代碼:
<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/icon_fengjng"
android:clipOrientation="vertical"
android:gravity="center">
</clip>
在MainActviity中用一個seekBar來控制ClipDrawable的level,調用的是它的setLevel()方法。最終可以讓它顯示不同的比例。
xml代碼:
<ImageView
android:id="@+id/iv_clip"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginTop="20dp"
android:src="@drawable/clip_drawable"/>
<SeekBar
android:id="@+id/seekbar"
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
然後是Activity檔案中:
ivClip = (ImageView) findViewById(R.id.iv_clip);
seekBar = (SeekBar) findViewById(R.id.seekbar);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int max = seekBar.getMax();
double scale =(double) progress /(double) max;
ClipDrawable drawable =(ClipDrawable) ivClip.getDrawable();
drawable.setLevel((int) (10000*scale));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
最終效果圖:
沒辦法錄制gif圖,看看别人的效果圖吧:https://blog.csdn.net/briblue/article/details/53528837
七、ScaleDrawable
ScaleDrawable是對一個Drawable進行縮放操作,ScaleDrawable與ClipDrawable類似,可以根據設定的level值對drawable進行縮放,但與ClipDrawable不同的是,ScaleDrawable還可以根據設定
android:scaleWidth
和
android:scaleHeight
進行相應百分比的縮放。
在xml檔案中使用scale作為根節點來建立RotateDrawable。
元素:
<scale>
定義一個ScaleDrawable,必須作為根元素。
- android:drawable Drawable 資源。必須的。引用一個drawable資源。
- android:scaleHeight 縮放的高度,以百分比的方式表示drawable的縮放。形式例如:100%,12.5%。
- android:scaleWidth 縮放的寬度,以百分比的方式表示drawable的縮放。形式例如:100%,12.5%。
- android:scaleGravity 指定縮放後的gravity的位置。必須是下面的一個或多個值(多個值之間用”|”分隔)
- top 将這個對象放在容器的頂部,不改變其大小。
- bottom 将這個對象放在容器的底部,不改變其大小。
- left 将這個對象放在容器的左部,不改變其大小。預設值。
- right 将這個對象放在容器的右部,不改變其大小。
- center_vertical 将對象放在垂直中間,不改變其大小。
- fill_vertical 如果需要的話,該對象的垂直尺寸将增加,以便完全填充它的容器。
- center_horizontal 将對象放在水準中間,不改變其大小。
- fill_horizontal 如果需要的話,該對象的水準尺寸将增加,以便完全填充它的容器。
- center 将對象放置在其容器的中心和水準軸的中心位置,而不改變它的大小。
- fill 如果需要的話,該對象的水準和垂直方向的大小将增加,使得完全填充它的容器。
- clip_vertical 可以設定為在其容器邊界上的頂部和/或底部邊緣的附加選項。該剪輯是基于垂直gravity:一個頂部gravity剪輯的底部邊緣,底部重力剪輯的頂部邊緣,既不剪輯兩個邊。
- clip_horizontal 與clip_vertical類似,隻是剪輯是基于水準gravity。
drawable:xml代碼:(縮放各設為50%)
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/icon_fengjng"
android:scaleGravity="left"
android:scaleHeight="50%"
android:scaleWidth="50%">
</scale>
然後在layout中使用:
<ImageView
android:id="@+id/iv_scale"
android:layout_width="match_parent"
android:layout_height="200dp"
android:src="@drawable/scale_drawable"/>
但是如果我們直接運作,發現并沒有顯示圖檔,檢視ScaleDrawable的源碼,發現draw()方法有判斷
getLevel() != 0
才繪制。而我們在沒有
setLevel()
時,預設
getLevel()
都是0。
是以如果我們想正常顯示圖檔,還需要設定drawable的level。如下:
ivScale = (ImageView) findViewById(R.id.iv_scale);
ScaleDrawable drawable = (ScaleDrawable) ivScale.getDrawable();
drawable.setLevel(1);
ScaleDrawable的
level
為0,不可見。為10000時,不縮放。我們一般設定level為1,這樣,圖檔就會根據xml中的android:scaleWidth和android:scaleHeight進行相應的縮放了。例如我們設定長寬縮放比例為50%,那麼圖檔長和寬都是原來的一倍,圖檔大小實際是原來大小的四分之一。
效果如下:
上面是設定縮放之後的,下面是原圖,圖檔變為原來的1/4.
八、 RotateDrawable
RotateDrawable 是對一個Drawable進行旋轉操作,可以根據level屬性控制這個drawable旋轉角度,也可以設定相對于它所在容器的對齊方式。
在xml檔案中使用rotate作為根節點來定義RotateDrawable.
drawable下-xml代碼:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/icon_fengjng"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
android:visible="true">
<!-- android:drawable ===Drawable 資源。必須的。引用一個drawable資源。-->
<!--android:fromDegrees == 整形。 從多少的角度開始旋轉-->
<!--android:toDegrees == 整形。 到多少的角度結束旋轉-->
<!--android:pivotX == 百分比。 旋轉的中心在圖檔X軸的百分比-->
<!--android:pivotY == 百分比。 旋轉的中心在圖檔Y軸的百分比-->
<!--android:visible == Boolean。是否可見。-->
</rotate>
這裡的pivotY、pivotX分别代表旋轉中心的位置,50%代表drawable的中心為旋轉中心。toDegrees代表最大可以旋轉的角度。在代碼中是通過level值确定的,這兩個值之間存在對應關系。如果設定最大旋轉角度為180,那麼Level=10000代表的就是旋轉180度,5000代表旋轉90度,如果最大旋轉角度設定為270度,那麼level=5000,就代表要旋轉135度。可以自己嘗試一下!!!(都是順時針旋轉)。
借鑒:https://blog.csdn.net/u011043551/article/details/61619282
layout使用 裡xml代碼:
<ImageView
android:id="@+id/iv_rotate"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginTop="20dp"
android:scaleType="fitXY"
android:background="@color/colorAccent"
android:src="@drawable/rotate_drawable"/>
在這裡我将ImageView的背景設定為紅色,drawable設定為圖檔顯示來源,通過執行個體你就會發現,旋轉的并不是imageView,僅僅隻是drawable旋轉了,然後再将旋轉後的drawable重新輸入到ImageView中。有背景色對比顯得更清楚。。。
acticity裡代碼:
private boolean isRotating = false;
private static final int update_rotate = 100;
private RotateDrawable rotateDrawable;
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case update_rotate:
int level = rotateDrawable.getLevel();
if(level >= 10000){
timer.cancel();
rotateDrawable.setLevel(0);
} else {
rotateDrawable.setLevel(level +100);
}
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drawable);
ivRotate = (ImageView) findViewById(R.id.iv_rotate);
rotateDrawable = (RotateDrawable) ivRotate.getDrawable();
rotateDrawable.setLevel(0);
ivRotate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
isRotating = true;
if(isRotating){
timer.start();
}
}
});
}
定時器:
private CountDownTimer timer = new CountDownTimer(Integer.MAX_VALUE,60) {
@Override
public void onTick(long millisUntilFinished) {
mHandler.sendEmptyMessage(update_rotate);
}
@Override
public void onFinish() {
isRotating = false;
}
};
通過點選圖檔,開啟定時器:在代碼中通過定時器和handler實作UI重新整理。
效果圖借鑒:
九、AnimationDrawable
AnimationDrawable 對應于Android中的幀動畫,就是把一系列的drawable按照一定的順序,一幀一幀的播放,并且可以使用android:oneshot屬性設定是否循環播放。
android:oneshot
清單屬性設定為true,它将循環一次,然後停止并保持最後一幀。如果它設定為false,則動畫将循環。
在xml檔案中使用animation-list作為根節點定義AnimationDrawable,使用item設定需要播放的每一幀使用的drawable資源,以及每一幀持續的時常。
下面定義一個包含五幀的AnimationDrawable,循環播放,幀間隔為300毫秒,代碼如下
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/icon_fengjng1"
android:duration="300"/>
<item android:drawable="@drawable/icon_fengjng2"
android:duration="300"/>
<item android:drawable="@drawable/icon_fengjng3"
android:duration="300"/>
<item android:drawable="@drawable/icon_fengjng4"
android:duration="300"/>
<item android:drawable="@drawable/icon_fengjng5"
android:duration="300"/>
</animation-list>
layout使用:
<ImageView
android:id="@+id/iv_anim"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/anim_drawable"/>
activity調用AnimationDrawable的 .start() 播放動畫:
ivAnim = (ImageView) findViewById(R.id.iv_anim);
animDrawable = (AnimationDrawable) ivAnim.getDrawable();
animDrawable.start();
需要注意的是,當我們在Activity的oncreate方法中調用start方法時會沒有任何效果,那是因為view還沒有初始化完成,無法播放動畫,是以需要使用handler來延遲播放動畫,具體實作代碼如下:
ivAnim = (ImageView) findViewById(R.id.iv_anim);
animDrawable = (AnimationDrawable) ivAnim.getDrawable();
//使用Handler
Handler animHandler = new Handler();
//調用PostDelay()方法去執行,最後的300表示每隔300重新循環執行一次,可以了解成定時器
animHandler.postDelayed(new Runnable() {
@Override
public void run() {
animDrawable.start();
}
},1000);
效果借鑒别人圖檔:
十、LayerDrawable
LayerDrawable 管理一組drawable,每個drawable都處于不同的層,當它們被繪制的時候,按照順序全部都繪制到畫布上。雖然這些drawable會有交差或者重疊的區域,但是它們是位于不同的層,彼此之間不會影響。
在xml檔案中使用layer-list作為根節點來定義LayerDrawable,通過item子節點定義每一層的drawable,layer-list沒有屬性節點,隻包含item子節點。它表示一種階層化的Drawable集合,通過将不同的Drawable放置在不同的層上面達到一種疊加的效果。
其中 可以包含多個
item
,每個item表示一個Drawable
item中可以通過
android:drawable
直接引用資源,如:
<
item
android:drawable
=
"@drawable/layer1"
/>
android:top
等表示Drawable相當于View上下左右的偏移量
drawable下xml代碼實作 文本輸入框:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/colorAccent"/>
</shape>
</item>
<item
android:bottom="6dp">
<shape android:shape="rectangle">
<solid android:color="#fff"/>
</shape>
</item>
<item
android:bottom="1dp"
android:left="1dp"
android:right="1dp">
<shape android:shape="rectangle">
<solid android:color="#fff"/>
</shape>
</item>
</layer-list>
使用:
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:hint="請輸入文字"
android:background="@drawable/layer_drawable"/>
效果圖:
十一、LevelListDrawable
對應于level-list标簽
擁有多個item,每個item都有maxLevel和minLevel
Level的範圍為0~10000
給定level後,會按從上至下的順序比對,直到找到範圍合适的Drawable,并傳回
item的level一定要降序或者升序
調用View的getBackground獲得Drawable對象,并調用setLevel設定等級level
ImageView的setImageLevel()能快速指定src引用的Drawable的Level
LevelListDrawable是根據level改變,選擇不同的Drawable,能用于實作進度條、音量調節等等
LevelListDrawable的使用:
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/icon_fengjng"
android:minLevel="0"
android:maxLevel="100"/>
<item android:drawable="@drawable/ic_person"
android:minLevel="101"
android:maxLevel="200"/>
</level-list>
layout布局:
<Button
android:id="@+id/btn_fengjing"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="風景"/>
<Button
android:id="@+id/btn_person"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="人物"
/>
<ImageView
android:id="@+id/iv_level"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/level_drawable"
/>
activity使用:
btnScenery = (Button) findViewById(R.id.btn_fengjing);
btnPerson = (Button) findViewById(R.id.btn_person);
ivLevel = (ImageView) findViewById(R.id.iv_level);
ivAnim.setImageLevel(50);
btnScenery.setOnClickListener(this);
btnPerson.setOnClickListener(this);
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_fengjing:
ivLevel.setImageLevel(50);
break;
case R.id.btn_person:
ivLevel.setImageLevel(150);
break;
}
}
效果圖:預設風景圖,點選後變為人物,再次點選風景按鈕,又變回風景,ImageView根據level值來查找顯示哪張圖檔:
十二、StateListDrawable:
StateListDrawable管理一組drawable,每一個drawable都對應着一組狀态,狀态的選擇類似于java中的switch-case組合,按照順序比較狀态,當遇到比對的狀态後,就傳回對應的drawable,是以需要把最精确的比對放置在最前面,按照從精确到粗略的順序排列。
StateListDrawable在Android中使用的非常廣泛,所有控件的背景基本上都使用了StateListDrawable,比如按鈕就具有很多狀态,按下狀态、選中狀态、預設狀态、禁用狀态等等,像這樣在不用的狀态下顯示效果不一樣的時候,就是需要使用StateListDrawable的時候。
在xml檔案中使用selector作為根節點來定義StateListDrawable,并使用item定義不同狀态下的drawable。定義如下XML:
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android"
android:constantSize="false" //StateListDrawable的固有大小是否根據狀态而改變,預設false=根據狀态而改變
android:dither="true" //是否開啟抖動-讓高品質圖檔在低品質螢幕上依舊效果好,預設true開啟
android:variablePadding="false" //padding是否根據狀态的改變而改變,不建議開啟(false)
>
<item android:state_pressed="true" //Button被按下後卻沒有松開的狀态
android:drawable="@color/colorAccent"/>
<item android:state_focused="true" //View擷取了焦點
android:drawable="@color/colorPrimary"/>
<item android:state_selected="true" //使用者選擇了View
android:drawable="@color/colorPrimary"/>
<item android:state_checked="true" //使用者選中了View,一般用于CheckBox這類在選中和沒有選中狀态之間切換的View
android:drawable="@drawable/ic_launcher_background"/>
<item android:state_enabled="true" //View處于可用狀态
android:drawable="@drawable/ic_launcher_foreground"/>
<item android:drawable="#FFFFFF"/> //預設Drawable: 按順序向下比對,需要放在最下方,因為可以比對任何狀态
</selector>
Drawable的使用:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!--這個是輸入框邊框變色-->
<item android:state_window_focused="false">
<shape android:shape="rectangle">
<solid
android:color="#FFFFFFFF"/>
<corners
android:radius="3dp"/>
<padding
android:left="10dp"
android:right="10dp"/>
<stroke
android:width="1dp"
android:color="#BDC7D8"/>
</shape>
</item>
<item android:state_focused="true" >
<shape android:shape="rectangle" >
<solid
android:color="#FFFFFFFF"/>
<corners
android:radius="3dp"/>
<padding
android:left="10dp"
android:right="10dp"/>
<stroke
android:width="1dp"
android:color="#cf1b18"/>
</shape>
</item>
</selector>
layout:檔案
<EditText
android:id="@+id/btn_selector_1"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:hint="請輸入資訊"
android:layout_margin="15dp"
android:singleLine="true"
android:layout_marginTop="20dp"
android:background="@drawable/selector_drawable"/>
效果圖: