Android Drawable完全解析(一):Drawable源码分析(上)
Android Drawable完全解析(一):Drawable源码分析(中)
Android Drawable完全解析(一):Drawable源码分析(下)
之前文章对Drawable的源码做了简单分析,下面总结一下Drawable比较常用的子类在xml及Java中的用法!
先上图看一下Drawable及其子类的继承关系:
最初看到这么多的子类,内心也是懵的,不过无妨,每种都在xml和java中用一遍就搞定,遇到感兴趣的子类还可以看一下它重写的方法,这也是我们以后自定义Drawable的基础!一个一个来!
1:BitmapDrawable
1.1:在xml中定义
//在Drawable文件夹中创建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代码中创建
View bitmap_java = findViewById(R.id.bitmap_java);
//用Java代码创建BitmapDrawable
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.img9);
BitmapDrawable bitmapDrawable = new BitmapDrawable(bitmap);
bitmapDrawable.setFilterBitmap(true);
bitmapDrawable.setAntiAlias(true);
bitmapDrawable.setDither(true);
//通过实验发现,tileMode和gravity属性同时设置,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"
是否抗锯齿,一般都设置为true;
2:android:dither="true"
是否允许抖动,一般都设置为true,可以使图片在低质量的屏幕上保持较好的显示效果,关于android:dither这篇文章写得很好:关于android布局的两个属性dither和tileMode;
3:android:filter="true"
是否开启滤波,当bitmap被缩放时候,filter可以保证bitmap实例外观的'平滑',一般都建议设置为true;
4:android:gravity
当bitmap实例比它所在的容器尺寸小的时候,gravity属性决定bitmap实例在哪个位置进行绘制
5:android:tileMode
决定bitmap的平铺模式(即bitmap实例尺寸小于其容器怎么填满容器),当设置了tileMode后,gravity属性失效,这一点在上面Java代码里面已经提及.
tileMode有以下四种可选值:
clamp:重复bitmap边缘的颜色;
disabled:不会重复绘制bitmap;
mirror:在水平和垂直方向按照镜像方式重复绘制bitmap;
repeat:保持bitmap原始方向在水平和垂直方向平铺;
2:ColorDrawable
ColorDrawable应该是最简单的Drawable,将指定颜色绘制到ColorDrawable实例所在的Canvas上.
2.1:在xml中定义
//在drawable文件夹下创建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代码中创建
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文件夹下创建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代码中创建
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代码中手动开启才会执行动画!
4:StateListDrawable
StateListDrawable对应于xml中的selector,是开发中经常使用的Drawable子类,比如一个按钮正常状态和按下时候不同的样式就是用StateListDrawable实现的
4.1:在xml中定义
//在drawable文件夹下创建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代码中创建
/**
* 根据正常状态和按压状态下 填充色,边框颜色及边框宽度,创建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){
//创建StateListDrawable实例
StateListDrawable drawable = new StateListDrawable();
//创建按压 及 正常状态下 对应的状态数组
int[] pressedState = new int[]{android.R.attr.state_pressed};
int[] normalState = new int[]{};
//创建按压 及 正常状态下 对应的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);
/**
* 执行{@link StateListDrawable#addState(int[], Drawable)}
* 设置不同状态下对应的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);
/**
* 设置新状态下将要进场的Drawable淡入耗时毫秒值
* {@link StateListDrawable#setEnterFadeDuration(int)}
* 设置旧状态下将要离场的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"
设置StateListDrawable实例不同状态下展示的Drawable尺寸是否保存一致,如果为true,则所有状态下Drawable尺寸都一致,是所有Drawable实例中最大尺寸;如果为false,不同状态下Drawable的尺寸由其自身决定!
2:android:variablePadding="false"
设置StateListDrawable实例的padding值是否根据状态改变发生变化,默认是false;
3:android:enterFadeDuration="2000"
对应{@link StateListDrawable#setEnterFadeDuration(int)}方法,设置新状态下将要进场的Drawable淡入耗时毫秒值
4:android:exitFadeDuration="2000"
对应{@link StateListDrawable#setExitFadeDuration(int)}方法,设置旧状态下将要离场的Drawable淡出耗时毫秒值
3,4两个属性的设置就实现了GIF中状态改变时的淡入淡出效果
5:AnimatedStateListDrawable
AnimatedStateListDrawable是StateListDrawable 的子类,除了可以指定不同状态下对应的Drawable,还可以为状态的改变设置过渡效果!
5.1:在xml中定义
//在drawable文件夹下创建animated-selector
<?xml version="1.0" encoding="utf-8"?>
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
<!--设置不同状态下展示的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" />
<!--为状态变化导致的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代码中创建暂未成功,哪位同学知道可以指教一下!
在Java代码中创建AnimatedStateListDrawable后,执行{@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"
指定当前过渡效果起始状态所对应的item的ID值.
如:<item android:id="@+id/normal"
2:android:toId="@id/pressed"
指定当前过渡效果终点状态所对应的item的ID值.
如:<item android:id="@+id/pressed"
3:android:reversible="true"
指定当前过渡效果是否可以反向执行.
如上面的例子中,按钮状态从普通变为按压,再从按压变为普通,会发现帧动画执行了2遍,执行顺序的相反的,从UI状态的逻辑上也更合理.
6:LevelListDrawable
LevelListDrawable对应level-list,也是一个Drawable实例的集合,其中每一个Drawable实例都有android:minLevel,android:maxLevel两个属性,当设置LevelListDrawable实例的level值,则会显示level在android:minLevel和android:maxLevel两个属性之间的Drawable实例.
6.1:在xml中定义
//在drawable文件夹下创建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代码中创建
对于LevelListDrawable实例,无论是不是在XML中定义并引用到布局文件中,要切换其展示Drawable实例,都需要在Java代码中调用
{@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()方法设置其中的Drawable实例展示比例,level值范围为[0,10000],越大显示比例越高.level为0则完全不显示,level为10000则完全显示不裁剪.
7.1:在xml中定义
//在drawable文件夹下创建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代码中创建
对于ClipDrawable,无论是在xml中声明后布局文件中引用,还是Java代码中创建,如果要调整其展示的比例,都需要在Java代码中调用{@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属性已经展示完毕,应该换下一种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代码中创建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代码中创建ClipDrawable实例方法:public ClipDrawable(Drawable drawable, int gravity, int orientation) { 中的gravity;
2:android:gravity="bottom"
定义裁剪后保留区域位于ClipDrawable容器的方位,在上面Activity的实验GIF录屏中可见不同类型的Gravity的作用!
Google官方介绍截图如下,感觉还是用到时候实验一下比较方便!
8:InsetDrawable
InsetDrawable也是一个Drawable容器,其中仅包含一个Drawble实例,InsetDrawable通过设置inset属性值来定义插入的Drawable实例与自身四边的距离.当我们需要设置一个视觉尺寸小于View尺寸的背景,InsetDrawable就能派上用场了!
8.1:在xml中定义
//在drawable文件夹下创建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代码中创建
//用Java代码创建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创建InsetDrawable实例时指定的间距:
8.4:常用属性介绍
1:android:insetLeft="20dp"
InsetDrawable内部插入的Drawable实例与其左边缘的距离
2:android:insetTop="20dp"
InsetDrawable内部插入的Drawable实例与其顶部的距离
3:android:insetRight="20dp"
InsetDrawable内部插入的Drawable实例与其右边缘的距离
4:android:insetBottom="20dp"
InsetDrawable内部插入的Drawable实例与其底部的距离
5:android:inset="20dp"
InsetDrawable内部插入的Drawable实例与其四边的距离
9:RotateDrawable
9.1:在xml中定义
//在drawable文件夹下创建
<?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代码中创建
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代码创建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是顺时针旋转,小于0是逆时针旋转;
2:android:toDegrees="360"
RotateDrawable实例最终角度,大于0是顺时针旋转,小于0是逆时针旋转;
3:android:pivotX="50%"
RotateDrawable实例旋转中心点X轴坐标相对自身位置;
4:android:pivotY="50%"
RotateDrawable实例旋转中心点Y轴坐标相对自身位置;
10:ScaleDrawable
是一个Drawable容器,通过设置level值来改变它包含的Drawable实例的宽高缩放值.level的值是[0,10000],0代表完全不可见,10000代表不缩放保持原始尺寸.
10.1:在xml中定义
//在drawable文件夹下创建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代码中创建
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可见,即使设置了宽高缩放比例,继续不断调整level值,图片也会从不可见逐渐变为原始尺寸
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实例.通过调用{@link DrawerArrowDrawable#setProgress(float)}方法来设置横线到箭头的进度值.
11.1:在xml中无法创建,只能通过Java代码创建
11.2:在Java代码中创建
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) {
//动画已结完整展示了一遍,停一会儿再重复
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中创建DrawerArrowDrawable实例
drawerArrowDrawable = new DrawerArrowDrawable(this);
//设置DrawerArrowDrawable实例的箭头指向
drawerArrowDrawable.setDirection(
DrawerArrowDrawable.ARROW_DIRECTION_LEFT);
//设置DrawerArrowDrawable实例绘制的横线和箭头的颜色
drawerArrowDrawable.setColor(Color.RED);
//设置DrawerArrowDrawable实例的箭头两边斜线长度
drawerArrowDrawable.setArrowHeadLength(160);
//设置DrawerArrowDrawable实例的箭头中轴长度
drawerArrowDrawable.setArrowShaftLength(320);
//设置DrawerArrowDrawable实例的三条横线的长度
drawerArrowDrawable.setBarLength(320);
//设置DrawerArrowDrawable实例的三条横线的宽度
drawerArrowDrawable.setBarThickness(64);
//设置DrawerArrowDrawable实例的三条横线间的间隔
drawerArrowDrawable.setGapSize(48);
//设置DrawerArrowDrawable实例状态发生变化过程中(由横线到箭头的过程),
//绘制的线条是否发生旋转
drawerArrowDrawable.setSpinEnabled(true);
//设置DrawerArrowDrawable实例状态改变的进度(0:横线 1:箭头)
drawerArrowDrawable.setProgress(0.00f);
v.setBackgroundDrawable(drawerArrowDrawable);
handler.obtainMessage().sendToTarget();
}
}
11.3:运行截屏
11.4:常用方法
见上面Java代码:
可以设置箭头方法,箭头的斜线和中轴长度,横线的长度,宽度和间距,通过不断设置progress不断调整状态改变的进度!
12:GradientDrawable
GradientDrawable代表颜色的渐变区域.在XML中是定义在shape内部的gradient,可以设置其颜色渐变的三种类型:
线性 android:type="linear"
放射 android:type="radial"
平铺 android:type="sweep"
12.1:在xml中定义
//在drawable文件夹下创建
//线性渐变
<?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代码中创建
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文件夹下创建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代码中创建
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layer_drawable);
//经过实验发现:调用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);
//需要直接调用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代码中创建LayerDrawable,想要改变其中Drawable子实例的尺寸,需要调用LayerDrawable.setLayerSize,直接调用其中Drawable子实例的setBounds方法不会起作用!!
其他的几个方法:setLayerInset,setLayerGravity,setLayerSize则设置了LayerDrawable中Drawable子实例与容器的间距,方位及尺寸!
14:NinePatchDrawable
NinePatchDrawable是一种 PNG 图像,在其中可定义当视图中的内容超出正常图像边界时 Android 缩放的可拉伸区域。此类图像通常指定为至少有一个尺寸设置为 "wrap_content" 的视图的背景,而且当视图扩展以适应内容时,九宫格图像也会扩展以匹配视图的大小.
最常用的地方就是聊天气泡!
14.1:在xml中定义
//在drawable文件夹下创建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代码中创建NinePatchDrawable
- xml中nine-patch下面的src属性设计的.9图,必须放在drawable文件夹下面,放在mipmap文件夹下识别不了
14.3:运行截屏
14.4:刚刚搜到一个在线制作.9.png的网站
15:RoundedBitmapDrawable
RoundedBitmapDrawable是一个可以绘制圆角或者直接绘制为圆形的Drawable子类.
15.1:无法在xml中定义
15.2:在Java代码中创建
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代码创建RoundedBitmapDrawable
v1 = findViewById(R.id.v1);
roundedBitmapDrawable =
RoundedBitmapDrawableFactory.create(
getResources(),
BitmapFactory.decodeResource(getResources(), R.mipmap.ii2)
);
roundedBitmapDrawable.setAntiAlias(true);
//1:设置Bitmap实例是否是圆形
roundedBitmapDrawable.setCircular(true);
v1.setBackgroundDrawable(roundedBitmapDrawable);
v2 = findViewById(R.id.v2);
//通过Java代码创建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代码中创建使用;
- 通过调用setCornerRadius或者setCircular来制定RoundedBitmapDrawable实例的圆角或者设置为圆形.
15.5:常用工具方法
/**
* 创建RoundedBitmapDrawable实例
*
* @param bitmapOri 原始Bitmap实例
* @param circular 是否是圆形
* @param strokeWidth 边框宽度
* @param cornerRadius 圆角半径值
* @return
*/
public static RoundedBitmapDrawable gainRoundedBitmapDrawableWithStroke(
Resources resources,
Bitmap bitmapOri,
boolean circular,
@ColorInt int strokeColor,
int strokeWidth,
float cornerRadius) {
//注意,要先执行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);
//设置RoundedBitmapDrawable实例绘制为圆形
roundedBitmapDrawable.setCircular(true);
} else {
//设置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代码中调用及截屏:
//使用工具类创建带边框的圆形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);
//使用工具类创建带边框的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);
使用工具类创建带边框的RoundedBitmapDrawable实例 截屏
16:TransitionDrawable
TransitionDrawable是可在两种可绘制对象资源之间交错淡出的可绘制对象.每个可绘制对象由单一<item>元素表示。不支持超过两个项目。要向前转换,请调用startTransition(),要向后转换,则调用reverseTransition()
16.1:在xml中定义
//在drawable文件夹下创建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代码中创建
对于TransitionDrawable,都必须在Java代码中手动调用startTransition才能展现出淡入淡出动画效果
****
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代码中设置间距
- TransitionDrawable必须在Java代码中手动调用startTransition(int durationMillis)来开启动画
17:RippleDrawable
17.1:在xml中定义
//在drawable文件夹下创建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下并未设置@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代码中创建
//Java代码创建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构造函数为例:
/**
* 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) {
****
}
关于RippleDrawable涟漪动画展示范围的详情情况,下面一篇文章写的很好:
Android L Ripple的使用
17.5:注
现在的手机系统大部分都5.0以上了,会发现很多手机原生Button点击效果比RippleDrawable还要丰富,单纯靠RippleDrawable还无法做到这样的效果,后续会介绍实现方法!
关于文章涉及到的代码,在用法总结完毕后,会在后续文章上传!