2020-02-14
原图:

效果图: 蓝色背景是我在布局里设置的,为了看居中的效果

- 注意:canvas的裁切和几何变换都要写在drawXXX()之前,因为先走canvas.drawXXX()的代码,然后会从下往上走。
canvas.save();与 canvas.restore();可以为一个节点(不知道这样理解对不对,反正这两方法之间的操作不会影响其他操作)
画圆形的图片: 两种方式,效果一样
方式一: 先裁切出一个圆的路径,再drawBitmap。其实代码是先执行画图,再执行的裁切
方式二: 在画圆时 使用Piant的着色器,图片着色器 着色图片
代码:
package com.app.yf.myapplication.view.activity.diy;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import com.app.yf.myapplication.R;
import androidx.annotation.Nullable;
@SuppressLint("AppCompatCustomView")
public class MyView extends ImageView {
private static final String TAG = "MyView";
private Context context;
// 控件的宽、高
private int viewWidth, viewHeight;
public MyView(Context context) {
super(context);
init(context);
}
public MyView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
this.context = context;
// 初始化画笔
initPaint();
}
private Paint mPaint; //画笔/颜料
private void initPaint() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
// mPaint.setStyle(Paint.Style.STROKE); //设置空心
// mPaint.setStyle(Paint.Style.FILL); //设置空心
// mPaint.setStrokeWidth(strokeWidth); //设置笔画宽度
mPaint.setColor(Color.GRAY); //设置颜色
}
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Log.i(TAG, "onMeasure: width: " + widthMeasureSpec);
Log.i(TAG, "onMeasure: height: " + heightMeasureSpec);
Log.i(TAG, "onMeasure: getWidth: " + getWidth());
Log.i(TAG, "onMeasure: getheight: " + getHeight());
Log.i(TAG, "onMeasure: getMeasuredWidth: " + getMeasuredWidth());
Log.i(TAG, "onMeasure: getMeasuredHeight: " + getMeasuredHeight());
// 控件的宽、高
viewWidth = getMeasuredWidth();
viewHeight = getMeasuredHeight();
}
@Override
protected void onDraw(Canvas canvas) {
// super.onDraw(canvas);
//如果是继ImagView,可以这样获取arc设置的Bitmap
Drawable drawable = getDrawable();
if (drawable == null || !(drawable instanceof BitmapDrawable)) {
super.onDraw(canvas);
return;
}
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
//这样可以直接取资源里的图片
// Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.a);
int bitmapWidth = bitmap.getWidth();
int bitmapHeight = bitmap.getHeight();
//画椭圆以及圆角时,取图片宽的一面撑到边的比例。控件宽高与图片宽高的比例 取小的比例
// float scale = Math.min(viewWidth * 1f / bitmapWidth, viewHeight * 1f / bitmapHeight);
//画正圆以及正方形圆角时。取图片窄的一面撑到边的比例
float minWidth = Math.min(bitmapWidth, bitmapHeight); //图片最小宽高
float scale = Math.min(viewWidth * 1f / minWidth, viewHeight * 1f / minWidth);
//计算移动到控件的中心位置的值
float translateToCenterX = (viewWidth - bitmapWidth) / 2;
float translateToCenterY = (viewHeight - bitmapHeight) / 2;
/**
* 注意:canvas的裁切和几何变换都要写在drawXXX()之前,因为先走canvas.drawXXX()的代码,然后会从下往上走。
* canvas.save();与 canvas.restore();可以为一个节点(不知道这样理解对不对)
*/
/**
* 画圆形的图片: 两种方式
*/
/**
* 方式一: 先裁切出一个圆的路径,再drawBitmap
*/
//在做范围裁切或几何变换时 要先保存 save(),再绘制,最后再恢复canvas.restore(),这样才不会影响其他的绘制
canvas.save();
//使用矩阵缩放 , Matrix可以实现所有的几何形变
Matrix matrixx = new Matrix();
matrixx.postTranslate(translateToCenterX, translateToCenterY); //移动到控件的中心位置
matrixx.postScale(scale, scale, viewWidth / 2, viewHeight / 2); //缩放
canvas.setMatrix(matrixx);//canvas设置矩阵
//裁切
Path path = new Path();
//椭圆,如果图片是正方形,自然就是正圆了
// path.addOval(0, 0, bitmapWidth, bitmapHeight, Path.Direction.CW);
//直接正圆
path.addCircle(bitmapWidth / 2, bitmapHeight / 2, minWidth / 2, Path.Direction.CW);
// path.addRoundRect(); //用这个方法就是圆角图片了
canvas.clipPath(path); //按一个路径裁切
//画图片
// canvas.drawBitmap(bitmap, matrixx, mPaint); //为啥不用这句,要用下面这句呢?因为我要要裁切,后做几何变换
canvas.drawBitmap(bitmap, 0, 0, mPaint);
canvas.restore(); //再恢复canvas
/**
* 方式二: 在画圆时 使用Piant的着色器,图片着色器 着色图片
*/
/* //在做范围裁切或几何变换时 要先保存 save(),再绘制,最后再恢复canvas.restore(),这样才不会影响其他的绘制
canvas.save();
//先移动到中心位置,再缩放
canvas.scale(scale, scale, viewWidth / 2, viewHeight / 2); //canvas缩放
canvas.translate(translateToCenterX, translateToCenterY); //移动到控件的中心位置
//图片着色器 着色图片
Shader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint.setShader(bitmapShader);
//画圆
canvas.drawCircle(bitmapWidth / 2, bitmapHeight / 2, minWidth / 2, mPaint);
mPaint.setShader(null); //清除着色器
canvas.restore(); //再恢复canvas*/
}
}
发现了没,按这个套路,也就可以画圆角的,三角的,五角星形的 等等,任何你能画出来的图形
下面我们用方式二画一个爱心裁切出图片的效果:
为什么用方式二? 感觉高级一点
/**
* ___________________________________________
*
* 使用方式二画一个心形的图片
*/
canvas.save();
//先移动到中心位置,再缩放
canvas.scale(scale, scale, viewWidth / 2, viewHeight / 2); //canvas缩放
canvas.translate(translateToCenterX, translateToCenterY); //移动到控件的中心位置
//先画一个心形路径 (宽高相等,还得在图片中间的位置)
Path path2 = new Path();
// 要取的宽高 , 心形的宽高, 图片宽高取小
float xinWidth = minWidth;
//左边圆的左边 = X向中心点 - 心形宽 / 2 ;上边 = Y向中心点 - 心形宽 / 2
float left = bitmapWidth / 2 - xinWidth / 2;
float top = bitmapHeight / 2 - xinWidth / 2;
path2.addArc(left, top, bitmapWidth / 2, bitmapHeight / 2, 140, 220);
//右边圆的右边 = 左边圆的左边 + 心形宽
path2.arcTo(bitmapWidth / 2, top, left + xinWidth, bitmapHeight / 2, 180, 220, false);
path2.lineTo(bitmapWidth / 2, top + xinWidth);
//图片着色器 着色图片
Shader bitmapShader2 = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint.setShader(bitmapShader2);
canvas.drawPath(path2, mPaint); //画心形图片
mPaint.setShader(null); //清除着色器
canvas.restore();
爱心图效果:

完事儿
网友评论