Android Drawable完全解析(一):Drawable源碼分析(上)
Android Drawable完全解析(一):Drawable源碼分析(中)
Android Drawable完全解析(一):Drawable源碼分析(下)
之前文章對Drawable的源碼做了簡單分析卡睦,下面總結(jié)一下Drawable比較常用的子類在xml及Java中的用法锦援!
先上圖看一下Drawable及其子類的繼承關(guān)系:
最初看到這么多的子類,內(nèi)心也是懵的寺惫,不過無妨形娇,每種都在xml和java中用一遍就搞定,遇到感興趣的子類還可以看一下它重寫的方法,這也是我們以后自定義Drawable的基礎(chǔ)!一個一個來!
1:BitmapDrawable
1.1:在xml中定義
//在Drawable文件夾中創(chuàng)建bitmap
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@mipmap/img_small"
android:antialias="true"
android:dither="true"
android:filter="true"
android:tileMode="mirror"
/>
//在布局文件中引用
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
android:background="@drawable/bg_tilemode_repeat"
/>
1.2:在Java代碼中創(chuàng)建
View bitmap_java = findViewById(R.id.bitmap_java);
//用Java代碼創(chuàng)建BitmapDrawable
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.img9);
BitmapDrawable bitmapDrawable = new BitmapDrawable(bitmap);
bitmapDrawable.setFilterBitmap(true);
bitmapDrawable.setAntiAlias(true);
bitmapDrawable.setDither(true);
//通過實驗發(fā)現(xiàn),tileMode和gravity屬性同時設(shè)置,gravity屬性失效
bitmapDrawable.setTileModeXY(Shader.TileMode.MIRROR,Shader.TileMode.MIRROR);
//bitmapDrawable.setGravity(Gravity.CENTER);
bitmap_java.setBackgroundDrawable(bitmapDrawable);
1.3:運行截屏
1.4:常用屬性介紹
1:android:antialias="true"
是否抗鋸齒,一般都設(shè)置為true;
2:android:dither="true"
是否允許抖動,一般都設(shè)置為true,可以使圖片在低質(zhì)量的屏幕上保持較好的顯示效果,關(guān)于android:dither這篇文章寫得很好:關(guān)于android布局的兩個屬性dither和tileMode;
3:android:filter="true"
是否開啟濾波,當bitmap被縮放時候,filter可以保證bitmap實例外觀的'平滑',一般都建議設(shè)置為true;
4:android:gravity
當bitmap實例比它所在的容器尺寸小的時候,gravity屬性決定bitmap實例在哪個位置進行繪制
5:android:tileMode
決定bitmap的平鋪模式(即bitmap實例尺寸小于其容器怎么填滿容器),當設(shè)置了tileMode后,gravity屬性失效,這一點在上面Java代碼里面已經(jīng)提及.
tileMode有以下四種可選值:
clamp:重復bitmap邊緣的顏色;
disabled:不會重復繪制bitmap;
mirror:在水平和垂直方向按照鏡像方式重復繪制bitmap;
repeat:保持bitmap原始方向在水平和垂直方向平鋪;
2:ColorDrawable
ColorDrawable應該是最簡單的Drawable,將指定顏色繪制到ColorDrawable實例所在的Canvas上.
2.1:在xml中定義
//在drawable文件夾下創(chuàng)建color
<?xml version="1.0" encoding="utf-8"?>
<color xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/colorAccent" />
//在布局文件中引用
<View
android:layout_width="match_parent"
android:layout_height="300px"
android:background="@drawable/bg_color_drawable"
/>
2.2:在Java代碼中創(chuàng)建
View v = findViewById(R.id.v);
ColorDrawable colorDrawable = new ColorDrawable(
getResources().getColor(R.color.colorPrimary));
v.setBackgroundDrawable(colorDrawable);
2.3:運行截屏
3:AnimationDrawable
3.1:在xml中定義,布局文件中引用后依然需要在Java代碼中開啟動畫
//在drawable文件夾下創(chuàng)建animation-list
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item
android:drawable="@mipmap/ii1"
android:duration="@android:integer/config_shortAnimTime" />
<item
android:drawable="@mipmap/ii2"
android:duration="@android:integer/config_shortAnimTime" />
<item
android:drawable="@mipmap/ii3"
android:duration="@android:integer/config_shortAnimTime" />
<item
android:drawable="@mipmap/ii4"
android:duration="@android:integer/config_shortAnimTime" />
<item
android:drawable="@mipmap/ii5"
android:duration="@android:integer/config_shortAnimTime" />
</animation-list>
//在布局文件中引用
<View
android:id="@+id/v1"
android:layout_width="500px"
android:layout_height="500px"
android:background="@drawable/bg_animation_list"
/>
//在布局文件中引用后,依然需要在java代碼中手動開啟動畫
View v1 = findViewById(R.id.v1);
//1:XML中指定的AnimationDrawable需要手動開啟
((AnimationDrawable)v1.getBackground()).start();
3.2:在Java代碼中創(chuàng)建
View v2 = findViewById(R.id.v2);
AnimationDrawable anim = new AnimationDrawable();
anim.setOneShot(false);
anim.addFrame(getResources().getDrawable(R.mipmap.ii1),200);
anim.addFrame(getResources().getDrawable(R.mipmap.ii2),200);
anim.addFrame(getResources().getDrawable(R.mipmap.ii3),200);
anim.addFrame(getResources().getDrawable(R.mipmap.ii4),200);
anim.addFrame(getResources().getDrawable(R.mipmap.ii5),200);
v2.setBackgroundDrawable(anim);
anim.start();
3.3:運行截屏
3.4:注意
對于AnimationDrawable,即使是在drawable文件下定義的animation-list在布局文件xml中被引用,也需要在Java代碼中手動開啟才會執(zhí)行動畫!
4:StateListDrawable
StateListDrawable對應于xml中的selector,是開發(fā)中經(jīng)常使用的Drawable子類,比如一個按鈕正常狀態(tài)和按下時候不同的樣式就是用StateListDrawable實現(xiàn)的
4.1:在xml中定義
//在drawable文件夾下創(chuàng)建selector
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:visible="true"
android:dither="true"
android:constantSize="true"
android:variablePadding="false"
android:enterFadeDuration="1000"
android:exitFadeDuration="1000">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="4dp"/>
<stroke android:color="@color/colorAccent" android:width="1dp"/>
<solid android:color="@color/colorPrimary"/>
</shape>
</item>
<item>
<shape android:shape="rectangle">
<corners android:radius="4dp"/>
<stroke android:color="@color/colorPrimary" android:width="1dp"/>
<solid android:color="@color/colorAccent"/>
</shape>
</item>
</selector>
//在布局文件中引用
<Button
android:id="@+id/v1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="StateListDrawable"
android:background="@drawable/bg_selector"
/>
4.2:在Java代碼中創(chuàng)建
/**
* 根據(jù)正常狀態(tài)和按壓狀態(tài)下 填充色,邊框顏色及邊框?qū)挾?創(chuàng)建StateListDrawable實例
* @param context
* @param normalColor
* @param normalStockColor
* @param pressedColor
* @param pressedStockColor
* @param radius
* @return
*/
public static StateListDrawable gainStateListDrawable(Context context,
@ColorInt int normalColor,
@ColorInt int normalStockColor,
@ColorInt int pressedColor,
@ColorInt int pressedStockColor,
float radius){
//創(chuàng)建StateListDrawable實例
StateListDrawable drawable = new StateListDrawable();
//創(chuàng)建按壓 及 正常狀態(tài)下 對應的狀態(tài)數(shù)組
int[] pressedState = new int[]{android.R.attr.state_pressed};
int[] normalState = new int[]{};
//創(chuàng)建按壓 及 正常狀態(tài)下 對應的Drawable實例
GradientDrawable pressedDrawable = new GradientDrawable();
pressedDrawable.setShape(GradientDrawable.RECTANGLE);
pressedDrawable.setStroke(2,pressedStockColor);
pressedDrawable.setCornerRadius(radius);
pressedDrawable.setColor(pressedColor);
GradientDrawable normalDrawable = new GradientDrawable();
normalDrawable.setShape(GradientDrawable.RECTANGLE);
normalDrawable.setStroke(2,normalStockColor);
normalDrawable.setCornerRadius(radius);
normalDrawable.setColor(normalColor);
/**
* 執(zhí)行{@link StateListDrawable#addState(int[], Drawable)}
* 設(shè)置不同狀態(tài)下對應的Drawable實例
*/
drawable.addState(pressedState,pressedDrawable);
drawable.addState(normalState,normalDrawable);
return drawable;
}
Button v2 = (Button) findViewById(R.id.v2);
StateListDrawable stateListDrawable = DrawableUtils.gainStateListDrawable(
this,
getResources().getColor(R.color.colorAccent),
getResources().getColor(R.color.colorPrimary),
getResources().getColor(R.color.colorPrimary),
getResources().getColor(R.color.colorAccent),8);
/**
* 設(shè)置新狀態(tài)下將要進場的Drawable淡入耗時毫秒值
* {@link StateListDrawable#setEnterFadeDuration(int)}
* 設(shè)置舊狀態(tài)下將要離場的Drawable淡出耗時毫秒值
* {@link StateListDrawable#setExitFadeDuration(int)}
*/
stateListDrawable.setEnterFadeDuration(500);
stateListDrawable.setExitFadeDuration(500);
v2.setBackgroundDrawable(stateListDrawable);
4.3:運行截屏
GIF中的淡入淡出效果并不是卡頓,下面4.4會介紹
4.4:常用屬性介紹
1:android:constantSize="true"
設(shè)置StateListDrawable實例不同狀態(tài)下展示的Drawable尺寸是否保存一致,如果為true,則所有狀態(tài)下Drawable尺寸都一致,是所有Drawable實例中最大尺寸;如果為false,不同狀態(tài)下Drawable的尺寸由其自身決定!
2:android:variablePadding="false"
設(shè)置StateListDrawable實例的padding值是否根據(jù)狀態(tài)改變發(fā)生變化,默認是false;
3:android:enterFadeDuration="2000"
對應{@link StateListDrawable#setEnterFadeDuration(int)}方法,設(shè)置新狀態(tài)下將要進場的Drawable淡入耗時毫秒值
4:android:exitFadeDuration="2000"
對應{@link StateListDrawable#setExitFadeDuration(int)}方法,設(shè)置舊狀態(tài)下將要離場的Drawable淡出耗時毫秒值
3,4兩個屬性的設(shè)置就實現(xiàn)了GIF中狀態(tài)改變時的淡入淡出效果
5:AnimatedStateListDrawable
AnimatedStateListDrawable是StateListDrawable 的子類,除了可以指定不同狀態(tài)下對應的Drawable,還可以為狀態(tài)的改變設(shè)置過渡效果!
5.1:在xml中定義
//在drawable文件夾下創(chuàng)建animated-selector
<?xml version="1.0" encoding="utf-8"?>
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
<!--設(shè)置不同狀態(tài)下展示的Drawable-->
<item
android:id="@+id/pressed"
android:drawable="@drawable/bg_shape_accent"
android:state_pressed="true" />
<item
android:id="@+id/normal"
android:drawable="@drawable/bg_shape_primary" />
<!--為狀態(tài)變化導致的Drawable實例切換添加過渡效果/一個幀動畫-->
<transition
android:fromId="@id/normal"
android:reversible="true"
android:toId="@id/pressed">
<animation-list>
<item
android:drawable="@drawable/bg_shape_primary"
android:duration="400"
/>
<item
android:drawable="@mipmap/ii1"
android:duration="400" />
<item
android:drawable="@mipmap/ii2"
android:duration="400" />
<item
android:drawable="@mipmap/ii3"
android:duration="400" />
<item
android:drawable="@mipmap/ii4"
android:duration="400" />
<item
android:drawable="@mipmap/ii5"
android:duration="400" />
<item
android:drawable="@drawable/bg_shape_accent"
android:duration="400"
/>
</animation-list>
</transition>
</animated-selector>
//在布局文件中引用
<View
android:id="@+id/v1"
android:layout_width="match_parent"
android:layout_height="800px"
android:background="@drawable/bg_animated_selector"
android:clickable="true"
/>
5.2:在Java代碼中創(chuàng)建暫未成功,哪位同學知道可以指教一下!
在Java代碼中創(chuàng)建AnimatedStateListDrawable后,執(zhí)行{@link AnimatedStateListDrawable#addState(int[], Drawable, int)}方法,int不知道如何賦值!
/**
* Add a new drawable to the set of keyframes.
*
* @param stateSet An array of resource IDs to associate with the keyframe
* @param drawable The drawable to show when in the specified state, may not be null
* @param id The unique identifier for the keyframe
*/
public void addState(@NonNull int[] stateSet, @NonNull Drawable drawable, int id) {
5.3:運行截屏
5.4:transition中屬性介紹
1:android:fromId="@id/normal"
指定當前過渡效果起始狀態(tài)所對應的item的ID值.
如:<item android:id="@+id/normal"
2:android:toId="@id/pressed"
指定當前過渡效果終點狀態(tài)所對應的item的ID值.
如:<item android:id="@+id/pressed"
3:android:reversible="true"
指定當前過渡效果是否可以反向執(zhí)行.
如上面的例子中,按鈕狀態(tài)從普通變?yōu)榘磯?再從按壓變?yōu)槠胀?會發(fā)現(xiàn)幀動畫執(zhí)行了2遍,執(zhí)行順序的相反的,從UI狀態(tài)的邏輯上也更合理.
6:LevelListDrawable
LevelListDrawable對應level-list,也是一個Drawable實例的集合,其中每一個Drawable實例都有android:minLevel,android:maxLevel兩個屬性,當設(shè)置LevelListDrawable實例的level值,則會顯示level在android:minLevel和android:maxLevel兩個屬性之間的Drawable實例.
6.1:在xml中定義
//在drawable文件夾下創(chuàng)建level-list
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@mipmap/battery0"
android:maxLevel="0"
android:minLevel="0" />
<item
android:drawable="@mipmap/battery1"
android:maxLevel="1"
android:minLevel="1" />
<item
android:drawable="@mipmap/battery2"
android:maxLevel="2"
android:minLevel="2" />
<item
android:drawable="@mipmap/battery3"
android:maxLevel="3"
android:minLevel="3" />
</level-list>
//在布局文件中引用
<View
android:id="@+id/v1"
android:layout_width="match_parent"
android:layout_height="400px"
android:background="@drawable/bg_level_list"
/>
6.2:在Java代碼中創(chuàng)建
對于LevelListDrawable實例,無論是不是在XML中定義并引用到布局文件中,要切換其展示Drawable實例,都需要在Java代碼中調(diào)用
{@link LevelListDrawable#setLevel(int)}方法
public class LevelListDrawableActivity extends AppCompatActivity {
private View v1;
private View v2;
LevelListDrawable drawable1;
LevelListDrawable drawable2;
private int currLevel = 0;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
drawable1.setLevel(currLevel);
drawable2.setLevel(currLevel);
currLevel = ++currLevel%3;
handler.sendMessageDelayed(handler.obtainMessage(),200);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_level_list_drawable);
v1 = findViewById(R.id.v1);
v2 = findViewById(R.id.v2);
drawable1 = (LevelListDrawable) v1.getBackground();
drawable2 = new LevelListDrawable();
drawable2.addLevel(0,0,getResources().getDrawable(R.mipmap.battery3));
drawable2.addLevel(1,1,getResources().getDrawable(R.mipmap.battery2));
drawable2.addLevel(2,2,getResources().getDrawable(R.mipmap.battery1));
drawable2.addLevel(3,3,getResources().getDrawable(R.mipmap.battery0));
v2.setBackgroundDrawable(drawable2);
handler.obtainMessage().sendToTarget();
}
}
6.3:運行截屏
6.4:常用屬性介紹
1:android:maxLevel="0"
該Drawable實例顯示所允許的最大level值.
2:android:minLevel="0"
該Drawable實例顯示所允許的最小level值.
7:ClipDrawable
準確來說,ClipDrawable是一個Drawable容器,其中只有一個Drawable實例,我們通過setLevel()方法設(shè)置其中的Drawable實例展示比例,level值范圍為[0,10000],越大顯示比例越高.level為0則完全不顯示,level為10000則完全顯示不裁剪.
7.1:在xml中定義
//在drawable文件夾下創(chuàng)建clip
<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
android:clipOrientation="horizontal"
android:drawable="@mipmap/img400267"
android:gravity="left"/>
<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
android:clipOrientation="vertical"
android:drawable="@mipmap/img400267"
android:gravity="bottom"/>
//在布局文件中引用
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.jet.mydrawable.ClipDrawableActivity"
android:fillViewport="true"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dp"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="xml:"
android:layout_marginBottom="8dp"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="310px"
android:orientation="horizontal"
>
<View
android:id="@+id/iv1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1.0"
android:background="@drawable/bg_clip_horizontal"
/>
<android.support.v4.widget.Space
android:layout_width="8dp"
android:layout_height="match_parent" />
<View
android:id="@+id/iv2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1.0"
android:background="@drawable/bg_clip_vertical"
/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Java: android:clipOrientation=horizontal"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
/>
<View
android:id="@+id/v_j1"
android:layout_width="800px"
android:layout_height="530px"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Java: android:clipOrientation=vertical"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
/>
<View
android:id="@+id/v_j2"
android:layout_width="800px"
android:layout_height="530px"
/>
</LinearLayout>
</ScrollView>
7.2:在Java代碼中創(chuàng)建
對于ClipDrawable,無論是在xml中聲明后布局文件中引用,還是Java代碼中創(chuàng)建,如果要調(diào)整其展示的比例,都需要在Java代碼中調(diào)用{@link ClipDrawable#setLevel(int)}方法
public class ClipDrawableActivity extends AppCompatActivity {
private int currLevel = 0;
private View iv1;
private View iv2;
private ClipDrawable cp1;
private ClipDrawable cp2;
private Handler handlerXml = new Handler() {
@Override
public void handleMessage(Message msg) {
cp1.setLevel(currLevel);
cp2.setLevel(currLevel);
if (currLevel >= 10000) {
currLevel = 0;
} else {
currLevel += 100;
}
handlerXml.sendEmptyMessageDelayed(1, 20);
}
};
private View v_j1;
private View v_j2;
private ClipDrawable cp_horizontal;
private ClipDrawable cp_vertical;
private int[] gravities = new int[]{
Gravity.LEFT,
Gravity.TOP,
Gravity.RIGHT,
Gravity.BOTTOM,
Gravity.CENTER,
Gravity.CENTER_HORIZONTAL,
Gravity.CENTER_VERTICAL,
Gravity.CLIP_HORIZONTAL,
Gravity.CLIP_VERTICAL,
Gravity.FILL,
Gravity.FILL_HORIZONTAL,
Gravity.FILL_VERTICAL,
Gravity.START,
Gravity.END
};
private int index = 0;
private int currLevelJava = 0;
private Handler handlerJava = new Handler() {
@Override
public void handleMessage(Message msg) {
if(index == 0&&currLevelJava==0){
Toast.makeText(ClipDrawableActivity.this,"開始試驗不同的Gravity值!",Toast.LENGTH_LONG).show();
}
cp_horizontal.setLevel(currLevelJava);
cp_vertical.setLevel(currLevelJava);
if(index == gravities.length-1&&currLevelJava==10000){
Toast.makeText(ClipDrawableActivity.this,"不同的Gravity值實驗完畢!",Toast.LENGTH_LONG).show();
}
if (currLevelJava >= 10000) {
currLevelJava = 0;
} else {
currLevelJava += 100;
}
if (currLevelJava == 0) {
//說明一種Gravity屬性已經(jīng)展示完畢,應該換下一種Gravity屬性了
index = (++index) % gravities.length;
cp_horizontal = new ClipDrawable(getResources().getDrawable(R.mipmap.img400267), gravities[index], ClipDrawable.HORIZONTAL);
cp_vertical = new ClipDrawable(getResources().getDrawable(R.mipmap.img400267), gravities[index], ClipDrawable.VERTICAL);
v_j1.setBackgroundDrawable(cp_horizontal);
v_j2.setBackgroundDrawable(cp_vertical);
}
handlerJava.sendEmptyMessageDelayed(1, 20);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_clip_drawable);
//1:在布局文件中直接引用clip
iv1 = findViewById(R.id.iv1);
iv2 = findViewById(R.id.iv2);
cp1 = (ClipDrawable) iv1.getBackground();
cp2 = (ClipDrawable) iv2.getBackground();
handlerXml.sendEmptyMessage(0);
//2:在Java代碼中創(chuàng)建ClipDrawable
v_j1 = findViewById(R.id.v_j1);
v_j2 = findViewById(R.id.v_j2);
cp_horizontal = new ClipDrawable(getResources().getDrawable(R.mipmap.img400267), gravities[index], ClipDrawable.HORIZONTAL);
cp_vertical = new ClipDrawable(getResources().getDrawable(R.mipmap.img400267), gravities[index], ClipDrawable.VERTICAL);
v_j1.setBackgroundDrawable(cp_horizontal);
v_j2.setBackgroundDrawable(cp_vertical);
handlerJava.sendEmptyMessage(0);
}
}
7.3:運行截屏
7.4:常用屬性介紹
1:android:clipOrientation="vertical"
定義裁剪的方向,水平或者垂直,對應Java代碼中創(chuàng)建ClipDrawable實例方法:public ClipDrawable(Drawable drawable, int gravity, int orientation) { 中的gravity;
2:android:gravity="bottom"
定義裁剪后保留區(qū)域位于ClipDrawable容器的方位,在上面Activity的實驗GIF錄屏中可見不同類型的Gravity的作用!
Google官方介紹截圖如下,感覺還是用到時候?qū)嶒炓幌卤容^方便!
8:InsetDrawable
InsetDrawable也是一個Drawable容器,其中僅包含一個Drawble實例,InsetDrawable通過設(shè)置inset屬性值來定義插入的Drawable實例與自身四邊的距離.當我們需要設(shè)置一個視覺尺寸小于View尺寸的背景,InsetDrawable就能派上用場了!
8.1:在xml中定義
//在drawable文件夾下創(chuàng)建inset
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@mipmap/img2"
android:insetBottom="40dp"
android:insetLeft="10dp"
android:insetRight="30dp"
android:insetTop="20dp"
android:visible="true">
</inset>
//在布局文件中引用
<View
android:layout_width="match_parent"
android:layout_height="400px"
android:background="@drawable/bg_inset"
/>
8.2:在Java代碼中創(chuàng)建
//用Java代碼創(chuàng)建InsetDrawable
v = findViewById(R.id.v);
float density = getResources().getDisplayMetrics().density;
insetDrawable = new InsetDrawable(
getResources().getDrawable(R.mipmap.img2),
(int)(density*10),(int)(density*20),
(int)(density*30),(int)(density*40));
v.setBackgroundDrawable(insetDrawable);
8.3:運行截屏
通過xml或Java創(chuàng)建InsetDrawable實例時指定的間距:
8.4:常用屬性介紹
1:android:insetLeft="20dp"
InsetDrawable內(nèi)部插入的Drawable實例與其左邊緣的距離
2:android:insetTop="20dp"
InsetDrawable內(nèi)部插入的Drawable實例與其頂部的距離
3:android:insetRight="20dp"
InsetDrawable內(nèi)部插入的Drawable實例與其右邊緣的距離
4:android:insetBottom="20dp"
InsetDrawable內(nèi)部插入的Drawable實例與其底部的距離
5:android:inset="20dp"
InsetDrawable內(nèi)部插入的Drawable實例與其四邊的距離
9:RotateDrawable
9.1:在xml中定義
//在drawable文件夾下創(chuàng)建
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@mipmap/rotate_round"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360"
android:visible="true">
</rotate>
//在布局文件中引用
<View
android:id="@+id/v1"
android:layout_width="200dp"
android:layout_height="200dp"
android:background="@drawable/bg_rotate"
/>
9.2:在Java代碼中創(chuàng)建
public class RotateDrawableActivity extends AppCompatActivity {
****
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if(run){
r1.setLevel(currLevel);
r2.setLevel(currLevel);
if(currLevel>=10000){
currLevel = 0;
}else{
currLevel += 10;
}
handler.sendEmptyMessageDelayed(0,10);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
****
v1 = findViewById(R.id.v1);
r1 = (RotateDrawable) v1.getBackground();
//通過Java代碼創(chuàng)建RotateDrawable
v2 = findViewById(R.id.v2);
r2 = new RotateDrawable();
//相當于xml中:android:drawable="@mipmap/rotate_round"
r2.setDrawable(getResources().getDrawable(R.mipmap.rotate_round));
//相當于xml中:android:pivotX="50%" android:pivotY="50%"
r2.setPivotX(0.5f);
r2.setPivotY(0.5f);
//相當于xml中:android:fromDegrees="0" android:toDegrees="360"
r2.setFromDegrees(0.0f);
r2.setToDegrees(-360.0f);
r2.setLevel(0);
v2.setBackgroundDrawable(r2);
handler.obtainMessage().sendToTarget();
}
****
}
9.3:運行截屏
9.4:常用屬性介紹
1:android:fromDegrees="0"
RotateDrawable實例起始角度,大于0是順時針旋轉(zhuǎn),小于0是逆時針旋轉(zhuǎn);
2:android:toDegrees="360"
RotateDrawable實例最終角度,大于0是順時針旋轉(zhuǎn),小于0是逆時針旋轉(zhuǎn);
3:android:pivotX="50%"
RotateDrawable實例旋轉(zhuǎn)中心點X軸坐標相對自身位置;
4:android:pivotY="50%"
RotateDrawable實例旋轉(zhuǎn)中心點Y軸坐標相對自身位置;
10:ScaleDrawable
是一個Drawable容器,通過設(shè)置level值來改變它包含的Drawable實例的寬高縮放值.level的值是[0,10000],0代表完全不可見,10000代表不縮放保持原始尺寸.
10.1:在xml中定義
//在drawable文件夾下創(chuàng)建scale
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@mipmap/img800534"
android:level="1"
android:scaleGravity="center"
android:scaleHeight="30%"
android:scaleWidth="30%">
</scale>
//在布局文件中引用
<View
android:layout_width="400px"
android:layout_height="400px"
android:layout_marginTop="8dp"
android:background="@drawable/bg_scale" />
10.2:在Java代碼中創(chuàng)建
public class ScaleDrawableActivity extends AppCompatActivity {
private View v1;
private View v2;
private ScaleDrawable scaleDrawable1;
private ScaleDrawable scaleDrawable2;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
int level = scaleDrawable2.getLevel();
if (level + 100 >= 10000) {
scaleDrawable2.setLevel(0);
} else {
scaleDrawable2.setLevel(level + 100);
}
handler.sendEmptyMessageDelayed(0, 20);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scale_drawable);
v1 = findViewById(R.id.v1);
v2 = findViewById(R.id.v2);
scaleDrawable1 = new ScaleDrawable(
getResources().getDrawable(R.mipmap.img800534),
Gravity.CENTER, 0.4f, 0.4f);
scaleDrawable2 = new ScaleDrawable(
getResources().getDrawable(R.mipmap.img800534),
Gravity.CENTER, 0.4f, 0.4f);
scaleDrawable1.setLevel(1);
scaleDrawable2.setLevel(1);
v1.setBackgroundDrawable(scaleDrawable1);
v2.setBackgroundDrawable(scaleDrawable2);
handler.obtainMessage().sendToTarget();
}
}
10.3:運行截屏
10.4:常用屬性介紹
通過上面Java代碼及GIF可見,即使設(shè)置了寬高縮放比例,繼續(xù)不斷調(diào)整level值,圖片也會從不可見逐漸變?yōu)樵汲叽?/strong>
11:DrawerArrowDrawable
A drawable that can draw a "Drawer hamburger" menu or an arrow and animate between them.The progress between the two states is controlled via[setProgress(float)]
這是Google官方介紹,通俗點講,DrawerArrowDrawable是一個可以繪制三條橫線或者箭頭,并且在兩者之間添加過渡動畫的Drawable實例.通過調(diào)用{@link DrawerArrowDrawable#setProgress(float)}方法來設(shè)置橫線到箭頭的進度值.
11.1:在xml中無法創(chuàng)建,只能通過Java代碼創(chuàng)建
11.2:在Java代碼中創(chuàng)建
public class DrawerArrowDrawableActivity extends AppCompatActivity {
View v;
DrawerArrowDrawable drawerArrowDrawable;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
float progress = drawerArrowDrawable.getProgress();
if (progress + 0.01f <= 1.00f) {
progress += 0.01f;
} else {
progress = 0.00f;
}
drawerArrowDrawable.setProgress(progress);
if (progress > 0.99f || progress <= 0.00f) {
//動畫已結(jié)完整展示了一遍,停一會兒再重復
handler.sendEmptyMessageDelayed(0, 1000);
Toast.makeText(DrawerArrowDrawableActivity.this,
""+progress, Toast.LENGTH_SHORT).show();
} else {
handler.sendEmptyMessageDelayed(0, 40);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drawer_arrow_drawable);
v = findViewById(R.id.v);
//在Java中創(chuàng)建DrawerArrowDrawable實例
drawerArrowDrawable = new DrawerArrowDrawable(this);
//設(shè)置DrawerArrowDrawable實例的箭頭指向
drawerArrowDrawable.setDirection(
DrawerArrowDrawable.ARROW_DIRECTION_LEFT);
//設(shè)置DrawerArrowDrawable實例繪制的橫線和箭頭的顏色
drawerArrowDrawable.setColor(Color.RED);
//設(shè)置DrawerArrowDrawable實例的箭頭兩邊斜線長度
drawerArrowDrawable.setArrowHeadLength(160);
//設(shè)置DrawerArrowDrawable實例的箭頭中軸長度
drawerArrowDrawable.setArrowShaftLength(320);
//設(shè)置DrawerArrowDrawable實例的三條橫線的長度
drawerArrowDrawable.setBarLength(320);
//設(shè)置DrawerArrowDrawable實例的三條橫線的寬度
drawerArrowDrawable.setBarThickness(64);
//設(shè)置DrawerArrowDrawable實例的三條橫線間的間隔
drawerArrowDrawable.setGapSize(48);
//設(shè)置DrawerArrowDrawable實例狀態(tài)發(fā)生變化過程中(由橫線到箭頭的過程),
//繪制的線條是否發(fā)生旋轉(zhuǎn)
drawerArrowDrawable.setSpinEnabled(true);
//設(shè)置DrawerArrowDrawable實例狀態(tài)改變的進度(0:橫線 1:箭頭)
drawerArrowDrawable.setProgress(0.00f);
v.setBackgroundDrawable(drawerArrowDrawable);
handler.obtainMessage().sendToTarget();
}
}
11.3:運行截屏
11.4:常用方法
見上面Java代碼:
可以設(shè)置箭頭方法,箭頭的斜線和中軸長度,橫線的長度,寬度和間距,通過不斷設(shè)置progress不斷調(diào)整狀態(tài)改變的進度!
12:GradientDrawable
GradientDrawable代表顏色的漸變區(qū)域.在XML中是定義在shape內(nèi)部的gradient,可以設(shè)置其顏色漸變的三種類型:
線性 android:type="linear"
放射 android:type="radial"
平鋪 android:type="sweep"
12.1:在xml中定義
//在drawable文件夾下創(chuàng)建
//線性漸變
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:dither="true"
android:shape="rectangle">
<gradient
android:angle="0"
android:centerColor="@android:color/holo_green_light"
android:centerX="0.5"
android:centerY="0.5"
android:endColor="@color/colorPrimaryDark"
android:startColor="@color/colorAccent"
android:type="linear"
android:gradientRadius="40dp"
/>
</shape>
//放射漸變
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:dither="true"
android:shape="rectangle">
<gradient
android:angle="0"
android:centerColor="@android:color/holo_green_light"
android:centerX="0.5"
android:centerY="0.5"
android:endColor="@color/colorPrimaryDark"
android:startColor="@color/colorAccent"
android:type="radial"
android:gradientRadius="70dp"
/>
</shape>
//平鋪漸變
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:dither="true"
android:shape="rectangle">
<gradient
android:angle="0"
android:centerColor="@android:color/holo_green_light"
android:centerX="0.5"
android:centerY="0.5"
android:endColor="@color/colorPrimaryDark"
android:startColor="@color/colorAccent"
android:type="sweep"
/>
</shape>
//在布局文件中引用
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
tools:context="com.jet.mydrawable.GradientDrawableActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dp">
<View
android:layout_width="match_parent"
android:layout_height="160dp"
android:layout_marginTop="8dp"
android:background="@drawable/bg_shape_gradient_linear" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="160dp"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<View
android:layout_width="0dp"
android:layout_height="160dp"
android:layout_weight="1.0"
android:background="@drawable/bg_shape_gradient_radial" />
<android.support.v4.widget.Space
android:layout_width="8dp"
android:layout_height="match_parent" />
<View
android:layout_width="0dp"
android:layout_height="160dp"
android:layout_weight="1.0"
android:background="@drawable/bg_shape_gradient_radial_noendcolor" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="160dp"
android:layout_marginTop="8dp"
android:background="@drawable/bg_shape_gradient_sweep" />
</LinearLayout>
</ScrollView>
12.2:在Java代碼中創(chuàng)建
v = findViewById(R.id.v);
gradientDrawable = new GradientDrawable(
GradientDrawable.Orientation.TR_BL,
new int[]{Color.RED,Color.YELLOW,Color.GREEN}
);
gradientDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT);
v.setBackgroundDrawable(gradientDrawable);
12.3:運行截屏
13:LayerDrawable
LayerDrawable是一個管理Drawable列表的Drawable子類,列表中每一個Drawable實例都按照其在列表中的順序進行繪制,最后一個Drawable實例繪制于頂部.LayerDrawable對應著xml中的layer-list,其中每一個Drawable對應著一個item.
13.1:在xml中定義
//在drawable文件夾下創(chuàng)建layer-list
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<bitmap
android:gravity="center"
android:src="@mipmap/ic_launcher_round"
android:tint="@android:color/holo_red_light" />
</item>
<item
android:left="10dp"
android:top="10dp">
<bitmap
android:gravity="center"
android:src="@mipmap/ic_launcher_round"
android:tint="@android:color/holo_green_light" />
</item>
<item
android:left="20dp"
android:top="20dp">
<bitmap
android:gravity="center"
android:src="@mipmap/ic_launcher_round"
android:tint="@android:color/holo_blue_light" />
</item>
</layer-list>
//在布局文件中引用
<View
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginBottom="8dp"
android:background="@drawable/bg_layer_list"
/>
13.2:在Java代碼中創(chuàng)建
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layer_drawable);
//經(jīng)過實驗發(fā)現(xiàn):調(diào)用LayerDrawable中Drawable子實例的setBounds,并不能改變LayerDrawable中繪制的Drawable實例的尺寸
v = findViewById(R.id.v);
Drawable drawable0 = DrawableCompat.wrap(getResources().getDrawable(R.mipmap.ic_launcher)).mutate();
// drawable0.setBounds(0,0,200,200);
drawable0.setTint(Color.RED);
Drawable drawable1 = DrawableCompat.wrap(getResources().getDrawable(R.mipmap.ic_launcher)).mutate();
// drawable1.setBounds(0,0,200,200);
drawable1.setTint(Color.GREEN);
Drawable drawable2 = DrawableCompat.wrap(getResources().getDrawable(R.mipmap.ic_launcher)).mutate();
// drawable2.setBounds(0,0,200,200);
drawable2.setTint(Color.BLUE);
Drawable[] drawables = new Drawable[3];
drawables[0] = drawable0;
drawables[1] = drawable1;
drawables[2] = drawable2;
layerDrawable = new LayerDrawable(drawables);
layerDrawable.setLayerInset(0,0,0,0,0);
layerDrawable.setLayerInset(1,80,80,0,0);
layerDrawable.setLayerInset(2,160,160,0,0);
layerDrawable.setLayerGravity(0,Gravity.TOP);
layerDrawable.setLayerGravity(1,Gravity.TOP);
layerDrawable.setLayerGravity(2,Gravity.TOP);
//需要直接調(diào)用LayerDrawable實例的setLayerSize來改變其中Drawable子實例的尺寸
layerDrawable.setLayerSize(0,100,100);
layerDrawable.setLayerSize(1,200,200);
layerDrawable.setLayerSize(2,300,300);
v.setBackgroundDrawable(layerDrawable);
}
13.3:運行截屏
13.4:LayerDrawable注意事項
直接在Java代碼中創(chuàng)建LayerDrawable,想要改變其中Drawable子實例的尺寸,需要調(diào)用LayerDrawable.setLayerSize,直接調(diào)用其中Drawable子實例的setBounds方法不會起作用!!
其他的幾個方法:setLayerInset,setLayerGravity,setLayerSize則設(shè)置了LayerDrawable中Drawable子實例與容器的間距,方位及尺寸!
14:NinePatchDrawable
NinePatchDrawable是一種 PNG 圖像仔粥,在其中可定義當視圖中的內(nèi)容超出正常圖像邊界時 Android 縮放的可拉伸區(qū)域挠铲。此類圖像通常指定為至少有一個尺寸設(shè)置為 "wrap_content" 的視圖的背景冕屯,而且當視圖擴展以適應內(nèi)容時,九宮格圖像也會擴展以匹配視圖的大小.
最常用的地方就是聊天氣泡!
14.1:在xml中定義
//在drawable文件夾下創(chuàng)建nine-patch
<?xml version="1.0" encoding="utf-8"?>
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
android:dither="true"
android:src="@drawable/bubble" />
//在布局文件中引用
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
****
android:padding="8dp"
android:orientation="vertical"
>
<EditText
android:padding="32dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_nine_patch"
/>
<EditText
android:padding="32dp"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:background="@drawable/bg_nine_patch"
/>
</LinearLayout>
14.2:注意
- 不建議在Java代碼中創(chuàng)建NinePatchDrawable
- xml中nine-patch下面的src屬性設(shè)計的.9圖,必須放在drawable文件夾下面,放在mipmap文件夾下識別不了
14.3:運行截屏
14.4:剛剛搜到一個在線制作.9.png的網(wǎng)站
15:RoundedBitmapDrawable
RoundedBitmapDrawable是一個可以繪制圓角或者直接繪制為圓形的Drawable子類.
15.1:無法在xml中定義
15.2:在Java代碼中創(chuàng)建
public class RoundedBitmapDrawableActivity extends AppCompatActivity {
private View v1;
private RoundedBitmapDrawable roundedBitmapDrawable;
private View v2;
private RoundedBitmapDrawable roundedBitmapDrawable2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rounded_bitmap_drawable);
//通過Java代碼創(chuàng)建RoundedBitmapDrawable
v1 = findViewById(R.id.v1);
roundedBitmapDrawable =
RoundedBitmapDrawableFactory.create(
getResources(),
BitmapFactory.decodeResource(getResources(), R.mipmap.ii2)
);
roundedBitmapDrawable.setAntiAlias(true);
//1:設(shè)置Bitmap實例是否是圓形
roundedBitmapDrawable.setCircular(true);
v1.setBackgroundDrawable(roundedBitmapDrawable);
v2 = findViewById(R.id.v2);
//通過Java代碼創(chuàng)建RoundedBitmapDrawable
roundedBitmapDrawable2 =
RoundedBitmapDrawableFactory.create(
getResources(),
BitmapFactory.decodeResource(getResources(), R.mipmap.ii3));
roundedBitmapDrawable2.setAntiAlias(true);
roundedBitmapDrawable2.setCornerRadius(64.0f);
v2.setBackgroundDrawable(roundedBitmapDrawable2);
}
}
15.3:運行截屏
15.4:注意事項
- RoundedBitmapDrawable只能在Java代碼中創(chuàng)建使用;
- 通過調(diào)用setCornerRadius或者setCircular來制定RoundedBitmapDrawable實例的圓角或者設(shè)置為圓形.
15.5:常用工具方法
/**
* 創(chuàng)建RoundedBitmapDrawable實例
*
* @param bitmapOri 原始Bitmap實例
* @param circular 是否是圓形
* @param strokeWidth 邊框?qū)挾? * @param cornerRadius 圓角半徑值
* @return
*/
public static RoundedBitmapDrawable gainRoundedBitmapDrawableWithStroke(
Resources resources,
Bitmap bitmapOri,
boolean circular,
@ColorInt int strokeColor,
int strokeWidth,
float cornerRadius) {
//注意,要先執(zhí)行Bitmap.copy(Config config, boolean isMutable),
//因為下面代碼 Canvas(bitmap)需要保證傳入的Bitmap實例必須是mutable
Bitmap bitmap = bitmapOri.copy(Bitmap.Config.ARGB_8888, true);
//Construct a canvas with the specified bitmap to draw into.
//The bitmap must be mutable.
Canvas canvas = new Canvas(bitmap);
Paint borderPaint = new Paint();
borderPaint.setAntiAlias(true);
borderPaint.setStyle(Paint.Style.STROKE);
borderPaint.setStrokeWidth(strokeWidth);
borderPaint.setColor(strokeColor);
//
RoundedBitmapDrawable roundedBitmapDrawable =
RoundedBitmapDrawableFactory.create(resources, bitmap);
if (circular) {
canvas.drawCircle(
roundedBitmapDrawable.getIntrinsicWidth() / 2,
roundedBitmapDrawable.getIntrinsicWidth() / 2,
roundedBitmapDrawable.getIntrinsicWidth() / 2,
borderPaint);
//設(shè)置RoundedBitmapDrawable實例繪制為圓形
roundedBitmapDrawable.setCircular(true);
} else {
//設(shè)置RoundedBitmapDrawable實例的圓角值
RectF rectF = new RectF();
rectF.set(0, 0,
roundedBitmapDrawable.getIntrinsicWidth(),
roundedBitmapDrawable.getIntrinsicHeight());
canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, borderPaint);
roundedBitmapDrawable.setCornerRadius(cornerRadius);
}
return roundedBitmapDrawable;
}
在Java代碼中調(diào)用及截屏:
//使用工具類創(chuàng)建帶邊框的圓形RoundedBitmapDrawable實例
v3 = findViewById(R.id.v3);
roundedBitmapDrawable3 = DrawableUtils.gainRoundedBitmapDrawableWithStroke(
getResources(),
BitmapFactory.decodeResource(getResources(), R.mipmap.ii4),
true,
Color.RED,
8,
32.0f);
v3.setBackgroundDrawable(roundedBitmapDrawable3);
//使用工具類創(chuàng)建帶邊框的RoundedBitmapDrawable實例
v4 = findViewById(R.id.v4);
roundedBitmapDrawable4 = DrawableUtils.gainRoundedBitmapDrawableWithStroke(
getResources(),
BitmapFactory.decodeResource(getResources(), R.mipmap.ii1),
false,
Color.GREEN,
32,
32.0f);
v4.setBackgroundDrawable(roundedBitmapDrawable4);
使用工具類創(chuàng)建帶邊框的RoundedBitmapDrawable實例 截屏
16:TransitionDrawable
TransitionDrawable是可在兩種可繪制對象資源之間交錯淡出的可繪制對象.每個可繪制對象由單一<item>元素表示拂苹。不支持超過兩個項目安聘。要向前轉(zhuǎn)換,請調(diào)用startTransition(),要向后轉(zhuǎn)換瓢棒,則調(diào)用reverseTransition()
16.1:在xml中定義
//在drawable文件夾下創(chuàng)建transition
<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/ii3"/>
<item android:drawable="@mipmap/ii4"/>
</transition>
//在布局文件中引用
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="xml:"
/>
<View
android:id="@+id/v1"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginBottom="8dp"
android:background="@drawable/bg_transition"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="Java:"
/>
<View
android:id="@+id/v2"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginBottom="8dp"
/>
16.2:在Java代碼中創(chuàng)建
對于TransitionDrawable,都必須在Java代碼中手動調(diào)用startTransition才能展現(xiàn)出淡入淡出動畫效果
****
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
transitionDrawable1.resetTransition();
transitionDrawable2.resetTransition();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_transition_drawable);
v1 = findViewById(R.id.v1);
v2 = findViewById(R.id.v2);
transitionDrawable1 = (TransitionDrawable) v1.getBackground();
transitionDrawable2 = new TransitionDrawable(
new Drawable[]{
getResources().getDrawable(R.mipmap.ii1),
getResources().getDrawable(R.mipmap.ii2)
});
v2.setBackgroundDrawable(transitionDrawable2);
//
transitionDrawable1.startTransition(4000);
transitionDrawable2.startTransition(4000);
handler.sendEmptyMessageDelayed(0,6000);
}
****
16.3:運行截屏
16.4:TransitionDrawable要點
- TransitionDrawable是LayerDrawable的子類,所以同樣支持在XML或者在Java代碼中設(shè)置間距
- TransitionDrawable必須在Java代碼中手動調(diào)用startTransition(int durationMillis)來開啟動畫
17:RippleDrawable
17.1:在xml中定義
//在drawable文件夾下創(chuàng)建ripple
//1:在ripple下添加id為@android:id/mask的Drawable子項,作為漣漪動畫的遮罩(展示范圍)
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/colorAccent">
<item
android:id="@android:id/mask"
android:drawable="@android:color/holo_green_light" />
</ripple>
//2:在ripple下并未設(shè)置@android:id/mask的Drawable實例作為漣漪動畫的遮罩(展示范圍),則漣漪動畫的展示范圍是其所在控件尺寸
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/colorAccent">
<item
android:drawable="@android:color/holo_green_light" />
</ripple>
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/colorAccent">
<item
android:drawable="@mipmap/ii1" />
</ripple>
//3:在ripple下并無其他Drawable子項,則漣漪動畫的展示范圍可能會超出RippleDrawable實例的范圍
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/colorAccent"/>
//在布局文件中引用
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.jet.mydrawable.LevelListDrawableActivity"
android:fillViewport="true"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dp"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="xml:"
/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="RippleDrawable Xml 1"
android:background="@drawable/bg_ripple_child_mask"
/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="RippleDrawable Xml 2"
android:background="@drawable/bg_ripple_child_color"
/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="RippleDrawable Xml 3"
android:background="@drawable/bg_ripple_child_drawable"
/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="RippleDrawable Xml 4"
android:background="@drawable/bg_ripple_nochild"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="Java:"
/>
<Button
android:id="@+id/v1"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginBottom="8dp"
android:text="RippleDrawable Java 1"
/>
<Button
android:id="@+id/v2"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginBottom="8dp"
android:text="RippleDrawable Java 2"
/>
</LinearLayout>
</ScrollView>
17.2:在Java代碼中創(chuàng)建
//Java代碼創(chuàng)建RippleDrawable
v1 = (Button) findViewById(R.id.v1);
v2 = (Button) findViewById(R.id.v2);
ColorStateList colorStateList = ColorStateList.valueOf(getResources().getColor(R.color.colorAccent));
Drawable content = getResources().getDrawable(R.mipmap.battery0);
ShapeDrawable mask1 = new ShapeDrawable();
mask1.setShape(new OvalShape());
ShapeDrawable mask2 = new ShapeDrawable();
mask2.setShape(new RectShape());
InsetDrawable insetDrawable = new InsetDrawable(mask2,48);
RippleDrawable rippleDrawable1 = new RippleDrawable(colorStateList,content,mask1);
RippleDrawable rippleDrawable2 = new RippleDrawable(colorStateList,content,insetDrawable);
v1.setBackgroundDrawable(rippleDrawable1);
v2.setBackgroundDrawable(rippleDrawable2);
17.3:運行截屏
17.4:屬性介紹
以Java中RippleDrawable構(gòu)造函數(shù)為例:
/**
* Creates a new ripple drawable with the specified ripple color and
* optional content and mask drawables.
* //漣漪動畫的顏色
* @param color The ripple color
* //漣漪動畫所在背景Drawable實例,在mask缺失情況下可以限定漣漪動畫的展示范圍
* @param content The content drawable, may be {@code null}
* //漣漪動畫展示范圍與mask(遮罩)相同
* @param mask The mask drawable, may be {@code null}
*/
public RippleDrawable(@NonNull ColorStateList color, @Nullable Drawable content,
@Nullable Drawable mask) {
****
}
關(guān)于RippleDrawable漣漪動畫展示范圍的詳情情況,下面一篇文章寫的很好:
Android L Ripple的使用
17.5:注
現(xiàn)在的手機系統(tǒng)大部分都5.0以上了,會發(fā)現(xiàn)很多手機原生Button點擊效果比RippleDrawable還要豐富,單純靠RippleDrawable還無法做到這樣的效果,后續(xù)會介紹實現(xiàn)方法!
關(guān)于文章涉及到的代碼浴韭,在用法總結(jié)完畢后,會在后續(xù)文章上傳脯宿!