前言
慕课网Android中的各种Drawable笔记
Drawable
1.Drawable是一个抽象类,是对可绘制物件的抽象。与View的区别是:没有事件和交互方法。
其子类有BitmapDrawable、LayerDrawable、StateListDrawable、ClipDrawable、TransitionDrawable、InsetDrawable。
BitmapDrawable
1.作用:设置图片缩放,平铺等。
2.设置:在资源文件res下创建drawable目录,并创建xxx.xml文件,代码如下,设置图片时,src中不能用svg的资源文件,否则会报错。
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:antialias="true"
android:dither="true"
android:src="@drawable/ic_ll"
android:tileMode="repeat">
</bitmap>
添加到控件的background或src属性上
3.属性
android:antialias:抗锯齿
android:tileMode:平铺模式
android:dither:抗抖动
4.效果
LayerDrawable
1.作用:管理一组drawable,使drawable资源按照列表顺序绘制,列表最后一个drawable绘制在最上层。
2.设置:在资源文件res下创建drawable目录,并创建xxx.xml文件,代码如下,bitmap可改为其他,比如shape
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:left="20dp"
android:top="20dp">
<!--这里放置第一张图片-->
<bitmap android:src="@drawable/ic_ll"/>
</item>
<item
android:left="20dp"
android:top="20dp">
<!--这里放置第二张图片-->
<bitmap android:src="@drawable/ic_location"/>
</item>
</layer-list>
添加到控件的background或src属性上
3.效果
StateListDrawable
1.作用:根据不同的状态提供不同的背景。就是常见的selector。
2.设置:在资源文件res下创建drawable目录,并创建xxx.xml文件,代码如下,这里以点击事件为例
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape>
<solid android:color="@color/colorPrimary"/>
</shape>
</item>
<!--不设置相当于将android:state_pressed设置成false-->
<item >
<shape>
<solid android:color="@color/colorAccent"/>
</shape>
</item>
</selector>
添加到控件的background或src属性上
LevelListDrawable
1.作用:管理一组drawable,每组都设置对应的最大值和最小值,作为选择该组的区间,这样可以根据外部设置的不同值选择不同的drawable。
2.设置:在资源文件res下创建drawable目录,并创建xxx.xml文件,代码如下,
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/ic_lamp_off"
android:maxLevel="5"
android:minLevel="1" />
<item
android:drawable="@drawable/ic_lamp_on"
android:maxLevel="10"
android:minLevel="6" />
</level-list>
添加到控件的background或src属性上
外部调用
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
public class DrawableActivity extends Activity {
private Button btnOn;
private Button btnOff;
private ImageView ivImage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drawable);
btnOn = findViewById(R.id.btn_on);
btnOff = findViewById(R.id.btn_off);
ivImage = findViewById(R.id.iv_image);
// 一定要先设置个默认状态,否则将不显示图片,这里默认显示ic_lamp_on
ivImage.setImageLevel(6);
btnOff.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 显示ic_lamp_off图片,只要将值设置在1-5
ivImage.setImageLevel(3);
}
});
btnOn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 显示ic_lamp_on图片,只要将值设置在6-10
ivImage.setImageLevel(6);
}
});
}
}
3.效果
TransitionDrawable
1.作用:是LayerDrawable的子类,不过只负责两层drawable,并提供了一个透明度变化的动画,可以控制从一层drawable过度到另外一层drawable的动画效果。
2.设置:在资源文件res下创建drawable目录,并创建xxx.xml文件,代码如下,
<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_lamp_off"/>
<item android:drawable="@drawable/ic_lamp_on" />
</transition>
添加到控件的background或src属性上
外部调用
import android.app.Activity;
import android.graphics.drawable.TransitionDrawable;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
public class DrawableActivity extends Activity {
private Button btnOn;
private Button btnOff;
private ImageView ivImage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drawable);
btnOn = findViewById(R.id.btn_on);
btnOff = findViewById(R.id.btn_off);
ivImage = findViewById(R.id.iv_image);
btnOff.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 先获取TransitionDrawable
TransitionDrawable drawable = (TransitionDrawable) ivImage.getDrawable();
// 开启过度变化,并设置时长
drawable.startTransition(5000);
}
});
btnOn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 先获取TransitionDrawable
TransitionDrawable drawable = (TransitionDrawable) ivImage.getDrawable();
// 开启反向过度变化,并设置时长
drawable.reverseTransition(5000);
}
});
}
}
3.效果
InsetDrawable
1.作用:表示一个drawable嵌入到另外一个drawable内部,并且在内部留一些间距,这一点很像drawable的padding属性。
2.设置:在资源文件res下创建drawable目录,并创建xxx.xml文件,代码如下,
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/shape_bitmap"
android:insetLeft="50dp"
android:insetRight="50dp"
android:insetTop="50dp"
android:insetBottom="50dp">
</inset>
添加到控件的background或src属性上
<ImageView
android:id="@+id/iv_image"
android:layout_width="200dp"
android:layout_height="200dp"
android:scaleType="centerInside"
android:background="@color/colorPrimary"
android:src="@drawable/inset_bitmap"/>
3.效果
ClipDrawable
1.介绍:ClipDrawable是通过设置一个Drawable的当前显示比例来裁剪出另一张Drawable,你可以通过调节这个比例来控制裁剪的宽高,以及裁剪内容占整个容器的权重,通过ClipDrawable的setLevel()方法调节显示比例可以实现类似Progress进度条的效果。ClipDrawable的level值范围在[0,10000],level的值越大裁剪的内容越少,如果level为10000时则完全显示。
2.设置:在资源文件res下创建drawable目录,并创建xxx.xml文件,代码如下,
<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
android:clipOrientation="horizontal"
android:drawable="@drawable/ic_lamp_off"
android:gravity="right">
</clip>
添加到控件的background或src属性上
3.属性
1、android:drawable;表示该ClipDrawable引用的drawable资源(这个属性必须有)。
2、android:clipOrientation;表示裁剪的方向。horizontal:水平方向,vertical:垂直方向。
3、android:gravity;指定从哪个地方裁剪。必须是下面一个或多个值(多个值之间用“|”分隔)
1.top 将这个对象放在容器的顶部,不改变其大小,当clipOrientation 是”vertical”,从底部(bottom)开始裁剪。
2.bottom 将这个对象放在容器的底部,不改变其大小。当clipOrientation 是 “vertical”,从顶部(top)开始裁剪。
3.left 将这个对象放在容器的左部,不改变其大小。当clipOrientation 是 “horizontal”,从右边(right)开始裁剪。
4.right 将这个对象放在容器的右部,不改变其大小。当clipOrientation 是 “horizontal”,从左边(left)开始裁剪。
5.center_vertical 将对象放在垂直中间,不改变其大小。裁剪的情况和”center“一样。
6.fill_vertical 垂直方向上不发生裁剪。(除非drawable的level是 0,才会不可见,表示全部裁剪完)
7.center_horizontal 将对象放在水平中间,不改变其大小。裁剪的情况和”center“一样。
8.fill_horizontal 水平方向上不发生裁剪。(除非drawable的level是 0,才会不可见,表示全部裁剪完)
9.center 将这个对象放在水平垂直坐标的中间,不改变其大小。当clipOrientation 是 “horizontal”裁剪发生在左右。当clipOrientation是”vertical”,裁剪发生在上下。
11.fill 填充整个容器,不会发生裁剪。(除非drawable的level是 0,才会不可见,表示全部裁剪完)。
12.clip_vertical 额外的选项,它能够把它的容器的上下边界,设置为子对象的上下边缘的裁剪边界。裁剪要基于对象垂直重力设置:如果重力设置为top,则裁剪下边,如果设置为bottom,则裁剪上边,否则则上下两边都要裁剪。
13.clip_horizontal 额外的选项,它能够把它的容器的左右边界,设置为子对象的左右边缘的裁剪边界。裁剪要基于对象垂直重力设置:如果重力设置为right,则裁剪左边,如果设置为left,则裁剪右边,否则则左右两边都要裁剪。
注意:android:gravity需要和android:clipOrientation配合使用,不同的组合,裁剪的效果也不同。
外部调用
import android.app.Activity;
import android.graphics.drawable.ClipDrawable;
import android.os.Bundle;
import android.widget.ImageView;
public class DrawableActivity extends Activity {
private ImageView ivImage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drawable);
ivImage = findViewById(R.id.iv_image);
ClipDrawable drawable = (ClipDrawable) ivImage.getDrawable();
drawable.setLevel(5000);
}
}
4.效果
自定义Drawable
实现步骤:
1.创建一个类并继承Drawable,实现其中的四个方法:draw、setAlpha、setColorFilter、getOpacity,如果需要改变宽和高,需要实现getIntrinsicHeight、getIntrinsicWidth方法。
2.在draw方法实现具体的绘制
3.将drawable设置到ImageView中
代码实现
1.自定义圆形图片Drawable
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
/**
*
* 设置圆形图片
*/
public class MyDrawable extends Drawable {
private Paint paint;
private Paint strokePaint;
private int width;
/**
* 通过构造方法传入所需要绘制的图片
*
* @param bitmap
*/
public MyDrawable(Bitmap bitmap) {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(bitmapShader);
strokePaint.setStyle(Paint.Style.STROKE);
strokePaint.setColor(Color.BLUE);
width = Math.min(bitmap.getWidth(), bitmap.getHeight());
// 设置描边
strokePaint.setStrokeWidth(20);
}
@Override
public void draw(@NonNull Canvas canvas) {
// 实现具体的绘制
int x = width / 2;
int y = width / 2;
int radius = width / 2;
canvas.drawCircle(x, y, radius, paint);
// 这里radius不能减20
canvas.drawCircle(x, y, radius - 10, strokePaint);
}
@Override
public void setAlpha(int alpha) {
paint.setAlpha(alpha);
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
paint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public int getIntrinsicHeight() {
return width;
}
@Override
public int getIntrinsicWidth() {
return width;
}
}
将Drawable设置到ImageView
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.widget.ImageView;
import com.lgf.myapplication.widget.MyDrawable;
public class DrawableActivity extends Activity {
private ImageView ivImage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drawable);
ivImage = findViewById(R.id.iv_image);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_ly);
ivImage.setImageDrawable(new MyDrawable(bitmap));
}
}
效果
2.自定义圆角矩形
package com.lgf.myapplication.widget;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
/**
* 设置圆角图片
*/
public class MyRoundDrawable extends Drawable {
private Paint paint;
private Paint strokePaint;
private Bitmap bitmap;
private RectF roundBoundsRectF;
private RectF roundRectF;
/**
* 通过构造方法传入所需要绘制的图片
*
* @param bitmap
*/
public MyRoundDrawable(Bitmap bitmap) {
this.bitmap = bitmap;
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(bitmapShader);
strokePaint.setStyle(Paint.Style.STROKE);
strokePaint.setColor(Color.BLUE);
// 设置描边
strokePaint.setStrokeWidth(20);
}
@Override
public void draw(@NonNull Canvas canvas) {
// 实现具体的绘制
// 30表示圆角弧度
canvas.drawRoundRect(roundRectF, 30, 30, paint);
canvas.drawRoundRect(roundBoundsRectF, 30, 30, strokePaint);
}
@Override
public void setBounds(int left, int top, int right, int bottom) {
super.setBounds(left, top, right, bottom);
roundRectF = new RectF(left, top, right, bottom);
roundBoundsRectF = new RectF(left + 10, top + 10, right - 10, bottom - 10);
}
@Override
public void setAlpha(int alpha) {
paint.setAlpha(alpha);
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
paint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public int getIntrinsicWidth() {
return bitmap.getWidth();
}
@Override
public int getIntrinsicHeight() {
return bitmap.getHeight();
}
}
效果