Paint,Path,Canvas

34 篇文章 0 订阅

PaintCanvasPath

1. Paint

Paint(画笔),保存了绘制几何图形文本位图样式颜色信息

关键词:coloralphastrokesolid线条圆角效果拐角风格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. clipPath
4. Matrix
5. Canvas调用了translate,scale等变换后,后续的操作都是基于变换后的Canvas,都会受到影响;所有我们采用canvas.save(),restore等方法来保存画布各个阶段状态,避免混乱
6. 离子爆炸效果


3. PathPathMeasure

Path(路径),可用于绘制直线,曲线构成的几何路径,还可根据路径绘制文字;常用API:移动,连线,闭合,添加图形等

一阶贝塞尔曲线(法):数据点和控制点rLineToRect类QQ消息数拉拽效果


  1. 项目中使用到一个左右端百分比效果(Paint使用):
    在这里插入图片描述

  2. 对应xml布局

 <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:layout_centerInParent="true"
        android:paddingLeft="20dp"
        android:paddingRight="20dp">

        <cn.cutcopy.canvas.PkLeftView
            android:id="@+id/pk1"
            android:layout_width="0dp"
            android:layout_height="48dp"
            android:layout_weight="1.0" />

        <cn.cutcopy.canvas.PkRightView
            android:layout_width="0dp"
            android:layout_height="48dp"
            android:layout_marginLeft="2dp"
            android:layout_weight="1.0" />

    </LinearLayout>
  1. 创建了2个自定义View,主要是坐标计算有点小繁琐
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 PkRightView 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 Paint mPaint;
    private Paint mPaintLine;

    private int lineH = PixelDpUtils.dp2px(1); // 画线宽度1/2

    public int xDown = 40; // 折角宽度 X

    public PkRightView(Context context) {
        this(context, null);
    }

    public PkRightView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PkRightView(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 = xDown;
        startY1 = lineH;
        stampPath.moveTo(startX1, startY1);

        // 2. 画水平线
        startX2 = mW - mH / 2;
        startY2 = lineH;

        stampPath.lineTo(startX2, startY2);

        // 3. 画圆弧
        if (arcRect == null) {
            arcRect = new RectF(mW - (mH - lineH), lineH, mW - lineH, mH - lineH);
        }
        stampPath.addArc(arcRect, 270, 180);

        // 4. 画直线
        startX3 = lineH;
        startY3 = mH - lineH;
        stampPath.lineTo(startX3, startY3);

        // 5.
        startX4 = xDown;
        startY4 = 0;
        stampPath.lineTo(startX4, startY4);

        // 6. 将Path利用Paint绘制出来
        canvas.drawPath(stampPath, mPaint);

        canvas.save();

        // 7.
        canvas.drawPath(stampPath, mPaintLine);
    }

}
  1. 本篇主要记录Paint基本用法,便于平常开发参考
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); // 圆角效果

6. 参考

  1. Xfermode
  2. drawBitmap的基本用法
  3. Andrdoid自定义View之canvas.clipPath(path)
  4. 一起看画布Android Canvas
  5. PathMeasure基本使用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

初心一点

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值