本文主要是讲自定义view中剪切圆形背景图并设置文字的实现过程和其中遇到的问题及相关技术介绍。是应领导要求在上一悬浮球界面(水波纹效果:点击打开链接)之后更改的圆形背景图:
剪切后 ->
起初只是简单的背景图片,但用于没有美工,自己学习PS后P出的图片又不太理想,所以只能自己来裁剪出圆形图片。
主要流程是:
1.读取本地图片为bitmap,关键方法:BitmapDrawable drawable = (BitmapDrawable) ContextCompat.getDrawable(context, R.drawable.background);
Bitmap bmp = drawable.getBitmap().copy(Bitmap.Config.ARGB_8888,true);。
2.将图片裁剪成正方形,并且在图片中间裁剪 方法: Bitmap.createBitmap(bitmap,裁剪的横坐标初始位置,裁剪的纵坐标初始位置,原始正方形边长,原始正方形边长);。
3.将裁剪后的正方形图片拉伸,将其拉伸为想要的正方形边长长度。
4.将最终的正方形图片裁剪为圆形,通过paint.setXfermode();方法,至于参数设置可以参考水波纹效果那篇文章下方的链接,您可以学习这个方法的作用及相关参数的作用。
代码实现:
public class View4 extends View {
private static final String TAG = "FlowBallView";
private String TEXT = "loading...";
public int width = 150;
public int height = 150;
private Context context;
private Paint paint;
private Paint paint1;
private int radius;
private int i = 0;
public View4(Context context) {
this(context, null);
}
public View4(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public View4(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
}
private void init() {
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.RED);
// paint.setTypeface(Typeface.DEFAULT_BOLD);//文字加粗
Log.d("view", "onDraw: 执行0");
paint1 = new Paint();
paint1.setAntiAlias(true);
paint1.setColor(Color.RED);
// paint1.setTypeface(Typeface.DEFAULT_BOLD);
radius = width / 2;
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
init();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.measure(0, 0);
BitmapDrawable drawable = (BitmapDrawable) ContextCompat.getDrawable(context, R.drawable.background);
Bitmap bmp = drawable.getBitmap().copy(Bitmap.Config.ARGB_8888,true);
Bitmap roundBitmap = getRoundBitmap(bmp, radius);// 截取后的圆形图片
canvas.drawBitmap(roundBitmap,0, 0,null);
paint.setTextSize(width/8);
paint1.setTextSize(width/6);
String text = "剩余流量";
float textWidth = paint.measureText(text); // 这里是需要关注的,文字宽度和高度的测量
Paint.FontMetrics metrics = paint.getFontMetrics(); // 这个类是文字高度测量必须使用的类,因为文字的高度不单单是其自身高,类似拼音的四线普
float baseLine = height / 2-(metrics.ascent + metrics.descent) - height/5; // 这里baseLine是基线,我之所以设置 (height/2- height/5)就是为了让文字根据圆形背景图高度而放置到其相应位置
float textWidth1 = paint1.measureText(TEXT);
Paint.FontMetrics metrics1 = paint1.getFontMetrics();
float baseLine1 = height / 2-(metrics1.ascent + metrics1.descent) ;
canvas.drawText(text,width / 2-textWidth/2,baseLine,paint);
canvas.drawText(TEXT,width / 2-textWidth1/2,baseLine1,paint1);
}
/**
* 获取裁剪后的圆形图片
* @param radius 半径
*/
public Bitmap getRoundBitmap(Bitmap bmp, int radius) {
Bitmap bitmap ;
Bitmap circleBitmap ;
int circle = radius*2;//绘制圆形直径长的正方形;
int scaler;//正方形边长
int x = 0,y = 0;
int circleWidth = bmp.getWidth();
int circleHeight = bmp.getHeight();
//先裁决出正方形图片
if(circleWidth>circleHeight){
scaler = circleHeight;
x = (circleWidth - circleHeight) / 2;// Bitmap.createBitmap 是用来裁剪图片的方法, /2 是为了保证裁剪的位置是图片中央
circleBitmap = Bitmap.createBitmap(bmp,x,y,scaler,scaler);
}else if (circleWidth<circleHeight){
scaler = circleWidth;
y =( circleHeight - circleWidth ) / 2;
circleBitmap = Bitmap.createBitmap(bmp,x,y,scaler,scaler);
}else{
circleBitmap = bmp;
}
if(circle!=circleBitmap.getWidth()||circle!=circleBitmap.getHeight()){
//设置正方形边长
bitmap = Bitmap.createScaledBitmap(circleBitmap,circle,circle,true);//Bitma.createScaledBitmap是拉伸图片的方法,参数2,3 是宽和长,true 是保证图片不失真
}else{
bitmap = circleBitmap;
}
Bitmap outPut = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), Bitmap.Config.ARGB_8888);//设置格式
//接下来开始画圆
Log.d("view", "圆");
Paint paint = new Paint();
paint.setDither(true);//图片不抖动
paint.setAntiAlias(true);//抗锯齿
paint.setARGB(255,255,255,255);//
//这步可以不写,但您如果调用了setARGB方法,那么您就必须将第一个参数设置为255或者调用下一步接着aint.setColor()方法以此来保证图片的透明度为"不透明",能清晰看到;当然您要是想要背景图片透明那么就可以设置此方法第一个参数
Rect rect = new Rect(0,0,bitmap.getWidth(),bitmap.getHeight());
Canvas canvas = new Canvas(outPut);
canvas.drawCircle(bitmap.getWidth() / 2,bitmap.getHeight() / 2,bitmap.getWidth()/2,paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap,rect,rect,paint);
return outPut;
}
}
有关Paint.FontMetrics和text文本的位置设置,这里有详细介绍,您点击链接就行: 文字测量详解
paint.setARGB(0,0,0,0);
这块可以这么写,也可以将其去掉 原因是 paint.setARGB()方法相当于paint.setAlpha(透明度方法)和paint.setColor(画笔颜色设置)两个方法结合 ,ARGB4个参数 ,参数1是透明度设置,234是颜色设置,查看源码其内部调用了setColor方法。当您调用setARGB方法就需要将第一个参数传值为255(这么做相当于设置paint透明度为不透明,也就是保证画笔画出的图片的透明度为不透明);
解释:
paint.setARGB(a,r,g,b); // 通过此方法您可以设置您的图片或者您画出的图案的透明度,以此来达到您想要的效果;比如:背景图片透明
a:透明度,取值范围为0~255,数值越小越透明。
r:红色的颜色值,取值范围为0~255。
g:绿色的颜色值,取值范围为0~255。
b:蓝色的颜色值,取值范围为0~255。
下图是对比效果:
这里是paint.setARGB()方法的简单介绍:http://book.51cto.com/art/201204/328260.htm
下面是绘制圆形的另一种方式,流程一样,但是画出圆的方式不同 :
Rect rect = new Rect(0,0,bitmap.getWidth(),bitmap.getHeight());
RectF rectF = new RectF(0,0,bitmap.getWidth(),bitmap.getHeight());
//正方形圆角边
Canvas canvas = new Canvas(outPut);
canvas.drawARGB(0,0,0,0);
//canvas.drawCircle(bitmap.getWidth() / 2,bitmap.getHeight() / 2,bitmap.getWidth()/2,paint);// 这是之前画圆的方式
// canvas.drawRoundRect(rectF,20 ,20 ,paint);
canvas.drawOval(rectF,paint); // 这里是另一种画圆的方式通过传入正方形,通过drawOval方法切出圆形
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap,rect,rect,paint);
return outPut;
下面是图片剪切的延伸,不只是剪出圆形图,还可以是更多的图形,但大致流程和原理都是类似的:
圆角正方形图片(想要圆角矩形,那么可以将剪切圆形的流程去掉正方形的剪切这步):
代码相对于圆形图片的剪切只是更改了canvas剪切的图形,想切什么图形那么就设置什么图形。
下面是更改的代码,其余未变
Rect rect = new Rect(0,0,bitmap.getWidth(),bitmap.getHeight());
RectF rectF = new RectF(0,0,bitmap.getWidth(),bitmap.getHeight()); //圆形矩形必须设置的实例对象,RectF ,4个参数: 分别是这个矩形四个边的位置
//正方形圆角边
Canvas canvas = new Canvas(outPut);
canvas.drawARGB(0,0,0,0);
//canvas.drawCircle(bitmap.getWidth() / 2,bitmap.getHeight() / 2,bitmap.getWidth()/2,paint); // 这里是上方剪切圆形而设置的圆形图。也就是通过canvas设置这个图形样式而实现的图片的剪切
canvas.drawRoundRect(rectF,20 ,20 ,paint); // 将剪切圆形图改为设置圆角矩形 4个参数: 1.矩形rectF 2.rx 圆角X方向半径 3.圆角Y方向半径 4.paint
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap,rect,rect,paint);
return outPut;
以后您想要再裁剪出什么图形,只需按这种方式通过canvas绘制图形结合paint的setXfermode()就可以裁剪出您想要的图片样式。