Android Paint,Path,Canvas
1. Paint
Paint(画笔),保存了绘制几何图形、文本和位图的样式和颜色信息
关键词:color,alpha,stroke,solid,线条圆角效果,拐角风格,xfermode,渲染器,TileMode
1. 线性渲染2. 环形渲染3. 扫描渲染4. 位图渲染5. 组合渲染
2. 图层混合模式
1. 离屏绘制2. 刮刮卡效果实现
3. 滤镜
1. 颜色矩阵(胶片效果等)2. 饱和度3. 亮度值
2. Canvas
Canvas(画布),通过画笔绘制几何图形,文本,路径和位图等
1. drawLine,drawBitmap,drawPath,drawText (绘制几何图形,文本,位图等)2. scale(缩放),rotate,translate(平移) (位置形状变换)3. clipPath4. Matrix5. Canvas调用了translate,scale等变换后,后续的操作都是基于变换后的Canvas,都会受到影响;所有我们采用canvas.save(),restore等方法来保存画布各个阶段状态,避免混乱6. 离子爆炸效果
3. Path、PathMeasure
Path(路径),可用于绘制直线,曲线构成的几何路径,还可根据路径绘制文字;常用API:移动,连线,闭合,添加图形等
一阶贝塞尔曲线(法):数据点和控制点、rLineTo、Rect、类QQ消息数拉拽效果
public class PkLeftView extends View { private static final String TAG = "GradientLayout"; private int mW, mH; // 控件,宽高 Path stampPath = new Path(); public int startX1, startY1; public int startX2, startY2; public int startX3, startY3; public int startX4, startY4; public RectF arcRect; private Shader mShader; private Bitmap mBitmap; private Paint mPaint; private Paint mPaintLine; private int lineH = PixelDpUtils.dp2px(1); // 画线宽度1/2 public int xDown = 40; // 折角宽度 X public PkLeftView(Context context) { this(context, null); } public PkLeftView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public PkLeftView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mPaintLine = new Paint(); //初始化 mPaintLine.setColor(Color.BLACK);// 设置颜色 mPaintLine.setStyle(Paint.Style.STROKE); //描边效果 mPaintLine.setAntiAlias(true); // 抗锯齿 mPaintLine.setStyle(Paint.Style.STROKE); //描边效果 mPaintLine.setStrokeWidth(lineH * 2);//描边宽度 mPaint = new Paint(); //初始化 mPaint.setAntiAlias(true); // 抗锯齿 mPaint.setStyle(Paint.Style.FILL); //描边效果 mPaint.setStrokeWidth(lineH * 2);//描边宽度 } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mW = getMeasuredWidth(); mH = getMeasuredHeight(); Log.i(TAG, "mW: " + mW); Log.i(TAG, "mW: " + mH); xDown = mW / 10; } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); Log.i(TAG, "left: " + left); Log.i(TAG, "top: " + top); Log.i(TAG, "right: " + right); Log.i(TAG, "bottom: " + bottom); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mShader = new LinearGradient(0, 0, 500, 500, new int[]{Color.RED, Color.BLUE, Color.GREEN}, new float[]{0.f, 0.7f, 1}, Shader.TileMode.REPEAT); mPaint.setShader(mShader); // 1. 首先移动到起始点 startX1 = mH / 2; startY1 = lineH; stampPath.moveTo(startX1, startY1); // 2. 画水平线 startX2 = mW - lineH; startY2 = lineH; stampPath.lineTo(startX2, startY2); // 3. 画倒角 startX3 = startX2 - xDown; startY3 = mH - lineH; stampPath.lineTo(startX3, startY3); // 4. 画下边 startX4 = mH / 2; startY4 = startY3; stampPath.lineTo(startX4, startY4); // // 5. 画圆弧 if (arcRect == null) { arcRect = new RectF(lineH, lineH, mH - lineH, mH - lineH); } stampPath.addArc(arcRect, 90, 180); // 6. 将Path利用Paint绘制出来 canvas.drawPath(stampPath, mPaint); canvas.save(); // 7. canvas.drawPath(stampPath, mPaintLine); } }
public class GradientLayout extends View { private Paint mPaint; private Shader mShader; private Bitmap mBitmap; public GradientLayout(Context context) { this(context, null); } public GradientLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public GradientLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.beauty); mPaint = new Paint(); //初始化 // mPaint.setColor(Color.RED);// 设置颜色 // mPaint.setARGB(255, 255, 255, 0); // 设置 Paint对象颜色,范围为0~255 // mPaint.setAlpha(200); // 设置alpha不透明度,范围为0~255 mPaint.setAntiAlias(true); // 抗锯齿 mPaint.setStyle(Paint.Style.FILL); //描边效果 // mPaint.setStrokeWidth(4);//描边宽度 // mPaint.setStrokeCap(Paint.Cap.ROUND); //圆角效果 // mPaint.setStrokeJoin(Paint.Join.MITER);//拐角风格 // mPaint.setShader(new SweepGradient(200, 200, Color.BLUE, Color.RED)); //设置环形渲染器 // mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN)); //设置图层混合模式 // mPaint.setColorFilter(new LightingColorFilter(0x00ffff, 0x000000)); //设置颜色过滤器 // mPaint.setFilterBitmap(true); //设置双线性过滤 // mPaint.setMaskFilter(new BlurMaskFilter(10, BlurMaskFilter.Blur.NORMAL));//设置画笔遮罩滤镜 ,传入度数和样式 // mPaint.setTextScaleX(2);// 设置文本缩放倍数 // mPaint.setTextSize(38);// 设置字体大小 // mPaint.setTextAlign(Paint.Align.LEFT);//对其方式 // mPaint.setUnderlineText(true);// 设置下划线 // // String str = "Android高级工程师"; // Rect rect = new Rect(); // mPaint.getTextBounds(str, 0, str.length(), rect); //测量文本大小,将文本大小信息存放在rect中 // mPaint.measureText(str); //获取文本的宽 // mPaint.getFontMetrics(); //获取字体度量对象 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); /** * 1.线性渲染,LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int colors[], @Nullable float positions[], @NonNull TileMode tile) * (x0,y0):渐变起始点坐标 * (x1,y1):渐变结束点坐标 * color0:渐变开始点颜色,16进制的颜色表示,必须要带有透明度 * color1:渐变结束颜色 * colors:渐变数组 * positions:位置数组,position的取值范围[0,1],作用是指定某个位置的颜色值,如果传null,渐变就线性变化。 * tile:用于指定控件区域大于指定的渐变区域时,空白区域的颜色填充方法 */ // mShader = new LinearGradient(0, 0, 500, 500, new int[]{Color.RED, Color.BLUE, Color.GREEN}, new float[]{0.f,0.7f,1}, Shader.TileMode.REPEAT); // mPaint.setShader(mShader); // canvas.drawCircle(250, 250, 250, mPaint); // canvas.drawRect(0,0,1000,1000, mPaint); /** * 环形渲染,RadialGradient(float centerX, float centerY, float radius, @ColorInt int colors[], @Nullable float stops[], TileMode tileMode) * centerX ,centerY:shader的中心坐标,开始渐变的坐标 * radius:渐变的半径 * centerColor,edgeColor:中心点渐变颜色,边界的渐变颜色 * colors:渐变颜色数组 * stoops:渐变位置数组,类似扫描渐变的positions数组,取值[0,1],中心点为0,半径到达位置为1.0f * tileMode:shader未覆盖以外的填充模式。 */ // mShader = new RadialGradient(250, 250, 250, new int[]{Color.GREEN, Color.YELLOW, Color.RED}, null, Shader.TileMode.CLAMP); // mPaint.setShader(mShader); // canvas.drawCircle(250, 250, 250, mPaint); /** * 扫描渲染,SweepGradient(float cx, float cy, @ColorInt int color0,int color1) * cx,cy 渐变中心坐标 * color0,color1:渐变开始结束颜色 * colors,positions:类似LinearGradient,用于多颜色渐变,positions为null时,根据颜色线性渐变 */ // mShader = new SweepGradient(250, 250, Color.RED, Color.GREEN); // mPaint.setShader(mShader); // canvas.drawCircle(250, 250, 250, mPaint); /** * 位图渲染,BitmapShader(@NonNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY) * Bitmap:构造shader使用的bitmap * tileX:X轴方向的TileMode * tileY:Y轴方向的TileMode REPEAT, 绘制区域超过渲染区域的部分,重复排版 CLAMP, 绘制区域超过渲染区域的部分,会以最后一个像素拉伸排版 MIRROR, 绘制区域超过渲染区域的部分,镜像翻转排版 */ // mShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.MIRROR); // mPaint.setShader(mShader); // canvas.drawRect(0,0,500, 500, mPaint); // canvas.drawCircle(250, 250, 250, mPaint); /** * 组合渲染, * ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, Xfermode mode) * ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, PorterDuff.Mode mode) * shaderA,shaderB:要混合的两种shader * Xfermode mode: 组合两种shader颜色的模式 * PorterDuff.Mode mode: 组合两种shader颜色的模式 */ BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); LinearGradient linearGradient = new LinearGradient(0, 0, 1000, 1600, new int[]{Color.RED, Color.GREEN, Color.BLUE}, null, Shader.TileMode.CLAMP); mShader = new ComposeShader(bitmapShader, linearGradient, PorterDuff.Mode.MULTIPLY); mPaint.setShader(mShader); canvas.drawCircle(250, 250, 250, mPaint); } }
1. 划线两端圆角效果
mPaint.setStrokeCap(Paint.Cap.ROUND); // 圆角效果
refs:
https://blog.csdn.net/zmm911zmm/article/details/89784920
https://www.codercto.com/a/43619.html
https://juejin.cn/post/6844903487570968584 | HenCoder Android 开发进阶: 自定义 View 1-2 Paint 详解 - 掘金
https://juejin.cn/post/6844903488460177416 | HenCoder Android 开发进阶:自定义 View 1-3 文字的绘制 - 掘金
https://juejin.cn/post/6844903489789755406 | HenCoder Android 开发进阶:自定义 View 1-4 Canvas 对绘制的辅助 - 掘金
https://juejin.cn/post/6844903491031269383 | HenCoder Android 自定义 View 1-5: 绘制顺序 - 掘金
https://juejin.cn/post/6844903494256689165 | HenCoder Android 自定义 View 1-6: 属性动画(上手篇) - 掘金
https://juejin.cn/post/6844903494940360711 | 【HenCoder Android 开发进阶】自定义 View 1-7:属性动画(进阶篇) - 掘金
https://juejin.cn/post/6844903496064434183 | # HenCoder Android 自定义 View 1-8 硬件加速 - 掘金
https://rengwuxian.com/ui-2-1/ | HenCoder Android 自定义 View 2-1 布局基础
https://rengwuxian.com/ui-2-2/ | HenCoder Android 自定义 View 2-2 全新定义 View 的尺寸
https://rengwuxian.com/ui-2-3/ | HenCoder Android 自定义 View 2-3 定制 Layout 的内部布局
https://rengwuxian.com/ui-3-1/ | HenCoder 自定义 View 3-1 触摸反馈,以及 HenCoder Plus