Drawable的实现类
官网上查看Drawable 的实现类,如ShapeDrawable,BitmapDrawable,ClipDrawable,RoundBitmapDrawable,StateListDrawableRoateDrawable。我们今天就是大致介绍一下比较常用的类。Drawable 是一种媒介,它可以把内容绘制到 Canvas 上。
GradientDrawable
一个创建图形的 Drawable,图形包括直线(line),
椭圆(oval),圆形(oval,当椭圆的宽高相等的时候就是圆形),矩形(rectangle),圆环(ring)。GradientDrawable
它在 XML 文件中对应的根节点为<Shape>
**下面是shape里一些相关属性:**
<shape> Android:shape=["rectangle" | "oval" | "line" | "ring"]
其中 rectagle 矩形,oval 椭圆,line 水平直线,ring 环形
**<shape> 标签中 子节点的常用属性:**
<gradient> 渐变:
Android:startColor
起始颜色
Android:endColor
结束颜色
Android:angle
渐变角度,0从左到右,90表示从下到上,数值为45的整数倍,默认为0;
Android:type
渐变的样式 liner线性渐变 radial环形渐变 sweep
<solid > 内部填充
Android:color
<stroke >描边
Android:width
描边的宽度
Android:color
描边的颜色
Android:dashWidth
表示'-'横线的宽度
Android:dashGap
表示'-'横线之间的距离
<corners >圆角
Android:radius
圆角的半径 值越大角越圆
Android:topRightRadius
右上圆角半径
Android:bottomLeftRadius
右下圆角角半径
Android:topLeftRadius
左上圆角半径
Android:bottomRightRadius
左下圆角半径
<padding >边界填充
android:bottom="1.0dip"
底部填充
android:left="1.0dip"
左边填充
android:right="1.0dip"
右边填充
android:top="0.0dip"
上面填充
<selector >
根据不同的选定状态来定义不同的现实效果
> 分为四大属性:
> android:state_selected 是否选中
> android:state_focused 是否获得焦点
> android:state_pressed 是否按压
> android:state_enabled 是否设置是否响应事件,指所有事件 另: android:state_window_focused
> 默认时的背景图片 引用位置:res/drawable/文件的名称.xml
直线
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="line">
<stroke android:width="5dp" android:color="#ffff0000"/>
</shape>
虚线
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="line"
>
<stroke android:width="5dp" android:color="@color/colorAccent"
android:dashGap="@dimen/cardview_default_radius"
android:dashWidth="@dimen/cardview_default_radius"
/>
<!--dashGap 虚线间隔-->
<!--dashWidth 虚线宽度-->
</shape>
椭圆或者圆形
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<stroke android:width="5dp" android:color="#ff0000"/>
</shape>
<?xml version="1.0" encoding="utf-8"?>
<!--宽高相等就是圆形了-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<stroke android:width="1dp" android:color="#ffff0000"/><!--描边-->
<size android:width="100dp" android:height="100dp"/>
<solid android:color="@color/colorAccent"/><!--填充颜色-->
</shape>
如果不用 Stroke( 描边,对应 Paint.STROKE ),而用Solid (填充,对应 Paint.FILL),会出现实心圆形。
<?xml version="1.0" encoding="utf-8"?>
<!--宽高相等就是圆形了-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<stroke android:width="1dp" android:color="#ffff0000"/><!--描边-->
<size android:width="100dp" android:height="100dp"/>
<solid android:color="@color/colorAccent"/><!--填充颜色-->
<!--渐变色-->
<gradient
android:startColor="@color/colorAccent"
android:endColor="@color/colorPrimary"/>
</shape>
矩形
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:radius="8dp"/>
<stroke
android:width="2dp"
android:color="@color/colorAccent"/>
<size
android:width="100dp"
android:height="100dp"/>
</shape>
圆环
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:innerRadius="100dp"
android:shape="ring"
android:thickness="10dp"
android:useLevel="false">
<solid
android:color="@color/colorAccent"/>
</shape>
- 这里要说下这个 useLevel, 只有在 LevelListDrawable 中才设置 true,这里要设置
false,否则显示不出来。- 其实 GradientDrawable 或者说是 ShapeDrawable 的绘制原理就是利用 Canvas.drawCircle() ,Canvas.drawRect() 等等方法(Canvas 我将在后面的文章介绍)。
LayerListDrawable
图层列表,就像我们平时把一张照片放在另外一张照片上,最后的照片在最上面。 LayerListDrawable 就是这样设计的。
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<solid android:color="@color/colorAccent"/>
</shape>
</item>
<item android:width="64dp" android:height="64dp">
<bitmap
android:gravity="center"
android:src="@android:drawable/ic_input_delete"/>
</item>
</layer-list>
StateListDrawable
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!--按钮被点击-->
<item android:state_pressed="true">
<shape>
<corners android:radius="10dp"/>
<solid android:color="@color/colorAccent"/>
</shape>
</item>
<item android:state_pressed="false">
<shape>
<corners android:radius="10dp"/>
<stroke
android:width="1dp"
android:color="#685252"/>
</shape>
</item>
</selector>
LevelListDrawable
经典案例:WiFi图标
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:maxLevel="0" android:drawable="@drawable/ic_wifi_signal_1" />
<item android:maxLevel="2" android:drawable="@drawable/ic_wifi_signal_2" />
<item android:maxLevel="5" android:drawable="@drawable/ic_wifi_signal_3" />
<item android:maxLevel="9" android:drawable="@drawable/ic_wifi_signal_4" />
</level-list>
maxLevel = 0 就是默认图片,看下默认效果
<ImageView
android:layout_centerInParent="true"
android:id="@+id/wifi_image"
android:onClick="onClickWifi"
android:background="@drawable/level_list_drawable"
android:layout_width="200dp"
android:layout_height="200dp"/>
private static int i = 1;
public void onClickWifi(View view) {
ImageView imageView = (ImageView) findViewById(R.id.wifi_image);
imageView.getBackground().setLevel(i++ % 10);
}
ColorDrawable
ColorDrawable colorDrawable = new ColorDrawable(Color.RED);
imageView.setBackground(colorDrawable);
RoundedBitmapDrawable
其实这个名字应该叫做 圆角图片,它是设置图片四个角的圆形半径。当图片是矩形的时候,就有四个圆角,再特殊一点,如果图片是正方形,正好圆角的半径为正方形边长的一半,那么它就是一个圆。
RoundedBitmapDrawable roundedBitmapDrawable2 =
RoundedBitmapDrawableFactory.create(getResources(),
BitmapFactory.decodeResource(getResources(),R.mipmap.image1));
//roundedBitmapDrawable2.setCornerRadius(150); //设置圆角为150度
roundedBitmapDrawable2.setCircular(true);//设置为圆形
roundedBitmapDrawable2.setBounds(10,10,10,10);
im01.setImageDrawable(roundedBitmapDrawable2);
有时候我们如果用的图片过大,就需要截取需要的哪一部分成正方形(矩形),然后生成圆形图片。 图片就会变形
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.sample_5);
// 创建 600*600 正方形 Bitmap,截取头像部分
Bitmap newBitmap = Bitmap.createBitmap(bitmap,
bitmap.getWidth() / 2 - 600 / 2, //x
100,// y
600,//width
600//height
);
// 回收没有用的 bitmap
bitmap.recycle();
RoundedBitmapDrawable roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(getResources(), newBitmap);
roundedBitmapDrawable.setCornerRadius(newBitmap.getWidth() / 2);
imageView.setImageDrawable(roundedBitmapDrawable);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.image3);
int height = bitmap.getHeight();//图片的高 1200
int width = bitmap.getWidth();//图片的宽 1920
mTextView.setText("height:"+height+"width:"+width);
//创建800*800的正方形Bitmap
/*
@param source 需要裁剪的bitmap
@param x 裁剪x点起始坐标(横向)
@param y 裁剪y点起始坐标(纵向)
@param width 裁剪后,新生成的bitmap的宽度
@param height 裁剪后,新生成的bitmap的高度
* */
Bitmap newBitmap = Bitmap.createBitmap(
bitmap,bitmap.getWidth() / 2-600/2,
50,
800,
800
);
//回收掉没用的bitmap
bitmap.recycle();
RoundedBitmapDrawable roundedBitmapDrawable =
RoundedBitmapDrawableFactory.create(getResources(),newBitmap);
roundedBitmapDrawable.setCornerRadius(newBitmap.getWidth()/2);//自己计算圆角度
//roundedBitmapDrawable.setCircular(true);//设置为圆形
im01.setImageDrawable(roundedBitmapDrawable);
不同大小的图片,需要裁减的位置也不一样,才能完成完美的图片效果,需要搞一个算法(。。。)
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.image2);
int height = bitmap.getHeight();//图片的高 1000
int width = bitmap.getWidth();//图片的宽 993
mTextView.setText("height:"+height+"width:"+width);
//创建800*800的正方形Bitmap
/*
@param source 需要裁剪的bitmap
@param x 裁剪x点起始坐标(横向)
@param y 裁剪y点起始坐标(纵向)
@param width 裁剪后,新生成的bitmap的宽度
@param height 裁剪后,新生成的bitmap的高度
* */
Bitmap newBitmap = Bitmap.createBitmap(
//x + width must be <= bitmap.width()
bitmap,bitmap.getWidth() / 2,
0,
350,
350
);
//回收掉没用的bitmap
bitmap.recycle();
Bitmap.Config ARGB_4444:每个像素占四位,即A=4,R=4,G=4,B=4,那么一个像素点占4+4+4+4=16位
Bitmap.Config ARGB_8888:每个像素占四位,即A=8,R=8,G=8,B=8,那么一个像素点占8+8+8+8=32位
Bitmap.Config RGB_565:每个像素占四位,即R=5,G=6,B=5,没有透明度,那么一个像素点占5+6+5=16位
Bitmap.Config ALPHA_8:每个像素占四位,只有透明度,没有颜色。
一般情况下我们都是使用的ARGB_8888,由此可知它是最占内存的,因为一个像素占32位,8位=1字节,所以一个像素占4字节的内存。假设有一张480x800的图片,如果格式为ARGB_8888,那么将会占用1500KB的内存
/*
* 使用RoundedBitmapDrawable,图片过大,系统会利用矩阵对我们的图片进行缩放处理,
* 系统将图片缩放成了正方形,所以图片里的东西看起来有点变形,我们利用代码加工图片,
* RoundedBitmapDrawable需要正方形,我们就给他正方形
* */
private Bitmap createRectBitmap(Bitmap bitmap){
int oldHeight = bitmap.getHeight();//原图高度
int oldWidth = bitmap.getWidth();//原图宽度
int borderWidth = 20 ; //边框宽度
//转换为正方形的宽高 取最小
int widthOrHeight = Math.min(oldHeight,oldWidth);
//最后的宽高 需要加上边框的宽度
int newBitmapWH = widthOrHeight + borderWidth;
Bitmap newBitmap = Bitmap.createBitmap(newBitmapWH,newBitmapWH,Bitmap.Config.ARGB_8888);
//画布
Canvas canvas = new Canvas(newBitmap);
//画布定义起始点坐标 (x,y)x:-700: y:20
int x = borderWidth + widthOrHeight - oldWidth;
int y = borderWidth + widthOrHeight - oldHeight;
Log.e("x:"+x,"y:"+y);
//裁剪后图像,注意X,Y要除以2 来进行一个中心裁剪
canvas.drawBitmap(bitmap, x/2, y/2, null);
//画布抗锯齿
canvas.setDrawFilter(new PaintFlagsDrawFilter(0,
Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));
Paint borderPaint = new Paint();
borderPaint.setStyle(Paint.Style.STROKE);//画笔mode
borderPaint.setStrokeWidth(borderWidth);//画笔宽度
borderPaint.setAntiAlias(true);//抗锯齿
borderPaint.setFilterBitmap(true);//抗锯齿
borderPaint.setColor(Color.WHITE);
//添加边框
/* @param cx要绘制的的圆的圆心的x坐标 @param cy要绘制的圆的圆心的y坐标
@param radius要绘制的线圈半径 @param paint用于绘制圆圈的油漆*/
canvas.drawCircle(canvas.getWidth()/2, canvas.getWidth()/2, newBitmapWH/2, borderPaint);
bitmap.recycle();//释放没用的bitmap
return newBitmap;
}
//使用上述方法
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.image3);
int height = bitmap.getHeight();//图片的高
int width = bitmap.getWidth();//图片的宽
mTextView.setText("height:"+height+"width:"+width);
Bitmap bitmap1 = createRectBitmap(bitmap);
RoundedBitmapDrawable roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(getResources(),bitmap1);
roundedBitmapDrawable.setGravity(Gravity.CENTER);//居中
roundedBitmapDrawable.setCircular(true);//设置为圆形
im01.setImageDrawable(roundedBitmapDrawable);
其他
/**
* 按宽/高缩放图片到指定大小并进行裁剪得到中间部分图片
*
* @param bitmap 源bitmap
* @param w 缩放后指定的宽度
* @param h 缩放后指定的高度
* @return 缩放后的中间部分图片
*/
public static Bitmap zoomBitmap(Bitmap bitmap, int w, int h) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
float scaleWidht, scaleHeight, x, y;
Bitmap newbmp;
Matrix matrix = new Matrix();
if (width > height) {
scaleWidht = ((float) h / height);
scaleHeight = ((float) h / height);
x = (width - w * height / h) / 2;//获取bitmap源文件中x做表需要偏移的像数大小
y = 0;
} else if (width < height) {
scaleWidht = ((float) w / width);
scaleHeight = ((float) w / width);
x = 0;
y = (height - h * width / w) / 2;//获取bitmap源文件中y做表需要偏移的像数大小
} else {
scaleWidht = ((float) w / width);
scaleHeight = ((float) w / width);
x = 0;
y = 0;
}
matrix.postScale(scaleWidht, scaleHeight);
try {
newbmp = Bitmap.createBitmap(bitmap, (int) x, (int) y, (int) (width - x), (int) (height - y), matrix,
true);//createBitmap()方法中定义的参数x+width要小于或等于bitmap.getWidth(),y+height要小于或等于bitmap.getHeight()
} catch (Exception e) {
e.printStackTrace();
return null;
}
return newbmp;
}
参考链接::不惜留恋_