图形的位置测量和xfermode的使用-自定义view(一)

2019-12-10  本文已影响0人  程序猿峰岑

图形绘制的基本要素:
1.onDraw(Canvas) --- 所有的尺寸都是像素
2.Canvas
3.Paint
4.坐标系
5.尺寸单位

onDraw绘图api
1.drawColor() ----------- 画颜色
2.drawLine() ----------- 画线
3.drawRect() ----------- 画矩形
4.drawRoundRect() ----- 画带有圆角的矩形
5.drawCircle() ---------- 画圈
6.drawOval(). ----------- 画圆
7.drawArc() ---------- 画弧
8.drawPaint() ---------- 画笔
9.DrawPath() ---------- 画轨迹
10.drawBitmap -------- 画图像
11.drawText() --------- 画文本

Path. ------ api

addxxx().
moveTo().
xxxTo()
PathMeasure().
setFillType()

画线

[图片上传中...(image.png-900126-1575875471719-0)]

画圆

image.png

onSizeChanged方法

这个方法是在onMeasure方法后调用,如果测量的结果不一样,这个方法会被调用。

Path画圆

path.addCircle(getWidth()/2,getHeight()/2,RADIUS, Path.Direction.CCW)

我讲下第四个参数,
Path.Direction.CW表示的是顺时针,Path.Direction.CCW逆时针
它的作用是多个图形的填充规则
为了更好的了解上面的参数,我们在画一个矩形
矩形图形代码:

path.addRect(getWidth()/2-RADIUS,getHeight()/2,getWidth()/2+RADIUS,getHeight()/2+RADIUS*2,Path.Direction.CCW);

图形如下:


image.png

现在我们再把矩形的CCW改为CW,又会是怎样的效果呢?


image.png
还有种方法是通过api path.setFillType()来填充
它有四种状态 分别是EVEN_ODD,INVAESE_EVEN_ODD,INVERSE_WINDING,WINDING

它们分别表示奇数填充,奇数反方向填充也就是偶数。包含取反填充和包含填充,后面两种应该很好理解,前面两种就不是那么好理解了。
其实他在绘制图形的时候是有一定的规则的,也就是如果是逆时针记为1。顺时针记为-1 相交处累加。图形解释如下:


image.png
我们在画一个比较大的圆。代码如下:
path.addCircle(getWidth()/2,getHeight()/2,RADIUS*2,Path.Direction.CCW);

运行结果如下:


image.png

自定义仪表盘

1.定义DashBoardView继承View
2.初始化画笔Paint

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

 private void init(){
        paint.setStrokeWidth(4);
        paint.setStyle(Paint.Style.STROKE);
    }

3.定义圆弧的大小以及劣弧的角度

 private static final int RADIUS = DisplayUtils.dpToPx(150);
    private static final int ANGLE = 120;

4.onDraw()方法使用canvas.drawArc

canvas.drawArc(getWidth()/2-RADIUS,getHeight()/2-RADIUS,
                getWidth()/2+RADIUS,getHeight()/2+RADIUS,90+ANGLE/2,
                360-ANGLE,false,paint);

先试下效果:


image.png

弧线画好了,接下来我们在画下刻度

1.实例化 Path dash = new Path()
2.定义刻度大小

dash.addRect(0,0,DisplayUtils.dpToPx(2),DisplayUtils.dpToPx(10), Path.Direction.CCW);

3.画刻度:
pathMeasure的作用就是计算轨迹的长度,我这里是画20刻度,这里就是用的轨迹长度减去刻度的宽度除以20 得到刻度之间的间隔宽度。

path.addArc(getWidth()/2-RADIUS,getHeight()/2-RADIUS,
                getWidth()/2+RADIUS,getHeight()/2+RADIUS,90+ANGLE/2,
                360-ANGLE);
        pathMeasure = new PathMeasure();
        pathMeasure.setPath(path,false);
        pathDashPathEffect = new PathDashPathEffect(dash,(pathMeasure.getLength()-DisplayUtils.dpToPx(2))/20,0, PathDashPathEffect.Style.ROTATE);

刻度这里就算画好了 接下来我们画指针
先设置指针长度:private static final int LENTH = DisplayUtils.dpToPx(100)
此处用到了正余弦相关的知识Math.cos()填入的内容为弧度,这里我们需要把角度转换为弧度Math.toRadians()

canvas.drawLine(getWidth()/2,getHeight()/2,
                getWidth()/2+(float)Math.cos(Math.toRadians(getAngleForMark(5)))*LENTH,
                getHeight()/2 + (float)Math.sin(Math.toRadians(getAngleForMark(5)))*LENTH,paint);

角度:

private float getAngleForMark(int mark){
        return 90 + ANGLE/2 + (360 - ANGLE)/20 * mark;
    }

效果图:


image.png

xfermode的使用

我这里使用xfermode做了一个头像的剪裁,核心代码如下:

Xfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);

canvas.drawOval(border,paint);
        int saveCount = canvas.saveLayer(cut,paint);
        canvas.drawOval(cut,paint);
        paint.setXfermode(xfermode);
        canvas.drawBitmap(avatar,PADDING,PADDING,paint);
        paint.setXfermode(null);
        canvas.restoreToCount(saveCount);

对于xfermode我们主要关注的就是选择的mode-PorterDuff.Mode.xxx
而对于选择的mode,那么我们就要对不同的mode它们的作用有所了解,为了了解这个mode,我们可以从developers中寻找答案:
原始图形:


image.png

选择不同mode的图形如下:

ADD

image.png

CLEAR

image.png

DARKEN

image.png

DST

image.png

DST_ATOP

image.png

DST_IN

image.png

DST_OUT

image.png

DST_OVER

image.png

LIGHTEN

image.png

MULTIPLY

image.png

OVERLAY

image.png

SCREEN

image.png

SRC


image.png

SRC_ATOP

image.png

SRC_IN

image.png

SRC_OUT

image.png

SRC_OVER

image.png

XOR

image.png

其实这些view还是有些粗糙的,今后有时间把仪表盘做成指南针或者速度仪。自定义头像可以做成项目中灵活引用可以自己设置参数,还有一个东西没讲到就是饼状图。我已经把这些自定义的东西已经上传到了github
源码

上一篇下一篇

猜你喜欢

热点阅读