Android Drawable完全解析(二):Drawable子類用法總結(jié)(一)

Android Drawable完全解析(一):Drawable源碼分析(上)
Android Drawable完全解析(一):Drawable源碼分析(中)
Android Drawable完全解析(一):Drawable源碼分析(下)

之前文章對Drawable的源碼做了簡單分析卡睦,下面總結(jié)一下Drawable比較常用的子類在xml及Java中的用法锦援!
先上圖看一下Drawable及其子類的繼承關(guān)系:


Drawable及其子類.png

最初看到這么多的子類,內(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:運行截屏
BitmapDrawable.jpg
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:運行截屏
ColorDrawable.png

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:運行截屏
AnimationDrawable錄屏.gif
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會介紹

StateListDrawable錄屏.gif

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:運行截屏
AnimatedStateListDrawable錄屏.gif
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:運行截屏
LevelListDrawable錄屏.gif
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:運行截屏
ClipDrawable在XML及Java中創(chuàng)建及試驗不同Gravity屬性的效果.gif
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ū)嶒炓幌卤容^方便!

ClipDrawable的Gravity屬性介紹.png

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:運行截屏

InsetDrawable截屏.jpg

通過xml或Java創(chuàng)建InsetDrawable實例時指定的間距:
InsetDrawable屬性效果.png

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:運行截屏
RotateDrawable錄屏.gif
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:運行截屏
ScaleDrawable錄屏.gif
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:運行截屏
DrawerArrowDrawable錄屏.gif
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:運行截屏
GradientDrawable截屏.jpg

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:運行截屏
LayerDrable截屏.png
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:運行截屏
9圖.png
14.4:剛剛搜到一個在線制作.9.png的網(wǎng)站

AndroidAssetStudio

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:運行截屏
RoundedBitmapDrawable.png
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實例 截屏

RoundedBitmapDrawable帶邊框.jpg

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:運行截屏
TransitionDrawable錄屏.gif
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:運行截屏
RippleDrawable錄屏.gif
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ù)文章上傳脯宿!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末念颈,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子连霉,更是在濱河造成了極大的恐慌舍肠,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件窘面,死亡現(xiàn)場離奇詭異翠语,居然都是意外死亡,警方通過查閱死者的電腦和手機财边,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進店門肌括,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人酣难,你說我怎么就攤上這事谍夭。” “怎么了憨募?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵紧索,是天一觀的道長。 經(jīng)常有香客問我菜谣,道長珠漂,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任尾膊,我火速辦了婚禮媳危,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘冈敛。我一直安慰自己待笑,他們只是感情好,可當我...
    茶點故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布抓谴。 她就那樣靜靜地躺著暮蹂,像睡著了一般寞缝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上仰泻,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天第租,我揣著相機與錄音,去河邊找鬼我纪。 笑死慎宾,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的浅悉。 我是一名探鬼主播趟据,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼术健!你這毒婦竟也來了汹碱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤荞估,失蹤者是張志新(化名)和其女友劉穎咳促,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體勘伺,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡跪腹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了飞醉。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冲茸。...
    茶點故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖缅帘,靈堂內(nèi)的尸體忽然破棺而出轴术,到底是詐尸還是另有隱情,我是刑警寧澤钦无,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布逗栽,位于F島的核電站,受9級特大地震影響失暂,放射性物質(zhì)發(fā)生泄漏彼宠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一趣席、第九天 我趴在偏房一處隱蔽的房頂上張望兵志。 院中可真熱鬧醇蝴,春花似錦宣肚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽按价。三九已至,卻和暖如春笙瑟,著一層夾襖步出監(jiān)牢的瞬間楼镐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工往枷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留框产,地道東北人。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓错洁,卻偏偏與公主長得像秉宿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子屯碴,可洞房花燭夜當晚...
    茶點故事閱讀 44,974評論 2 355

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,159評論 25 707
  • ¥開啟¥ 【iAPP實現(xiàn)進入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程描睦,因...
    小菜c閱讀 6,424評論 0 17
  • 時間過的很快,2012年接近了尾聲导而,學校每年都會舉辦盛大的元旦晚會忱叭,今年也不例外。晚會地點是在學校體育館今艺,學生可自...
    安小倫閱讀 261評論 0 2
  • 【默默耕耘】2017.02011 day 80 Saturday 1.故事書:小朋友讓爸爸給他們讀了一遍杰瑞的冷靜...
    ysmalina閱讀 100評論 0 0
  • 正值立秋韵丑,陰雨。余小憩于門市虚缎。睜眼埂息,忽一鼠堂而皇之立于地板之上,其似有拳頭大小遥巴,全身通黑千康,烏珠間又似帶白點,企圖...
    千里清風閱讀 392評論 1 3