一步一步教你什么样贯彻Ali芝麻信用分仪表盘效果,html5上学笔记陆

绘制普通直线,先看功能图:

绘制普通直线,先看功效图:

原稿地址:

先是看望效果图:

澳门葡京 1

澳门葡京 2

澳门葡京 ,废话不多说,先看下效果:

澳门葡京 3

兑今世码如下:

得以完毕代码如下:

澳门葡京 4参照功用图

那边写图片描述

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script>
        function drawGraph(id)
        {
            var canvas=document.getElementById(id);
            var context=canvas.getContext("2d");
            context.fillStyle="#CC00FF" //最外层canvas颜色
            context.fillRect(0,0,300,300)//最外层canvas区域
            context.beginPath()
            context.fillStyle="#008B8B"//填充颜色
            context.strokeStyle="#FFFF00"//线的颜色
            var dx=150
            var dy=150
            var s=100
            var dig=Math.PI/15*11
            for(var i=0;i<30;i++)
            {
                var x=Math.sin(i*dig)
                var y=Math.cos(i*dig)
                context.lineTo(dx+x*s,dy+y*s)
            }
            context.closePath()//关闭路径
            context.fill()//填充颜色
            context.stroke()
        }
    </script>
</head>
<body onload="drawGraph('canvasId')">
<canvas id="canvasId" width="300" height="400"></canvas>
</body>
</html>
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script>
        function drawGraph(id)
        {
            var canvas=document.getElementById(id);
            var context=canvas.getContext("2d");
            context.fillStyle="#CC00FF" //最外层canvas颜色
            context.fillRect(0,0,300,300)//最外层canvas区域
            context.beginPath()
            context.fillStyle="#008B8B"//填充颜色
            context.strokeStyle="#FFFF00"//线的颜色
            var dx=150
            var dy=150
            var s=100
            var dig=Math.PI/15*11
            for(var i=0;i<30;i++)
            {
                var x=Math.sin(i*dig)
                var y=Math.cos(i*dig)
                context.lineTo(dx+x*s,dy+y*s)
            }
            context.closePath()//关闭路径
            context.fill()//填充颜色
            context.stroke()
        }
    </script>
</head>
<body onload="drawGraph('canvasId')">
<canvas id="canvasId" width="300" height="400"></canvas>
</body>
</html>

该作用壹眼看上去比较轻巧,但其关联的知识点依旧挺多的。尤其是亟需读者对android.graphics包下的API有料定的问询。先对关联到的知识点罗列如下,还不是很领悟的读者可以先活动百度做个轻松的读书,对持续文章的敞亮会有相当大扶持。

先简要说一下那边须求涉及到的知识点:

一步一步教你什么样贯彻Ali芝麻信用分仪表盘效果,html5上学笔记陆。 绘制贝塞尔曲线

 绘制贝塞尔曲线

  • Paint、Canvas那七个基础的类必须熟稔。
  • 用作渲染的Shader类及其子类,以及后文中动用的是SweepGradient梯度渲染,用作渐变圆环,供给了然。
  • canvas.save() & canvas.restore() 的效益与涉及。
  • 由Paint引申的PathEffect、波特DuffXfermode,已经Matrix等类要有个宗旨的定义。
  • 图层绘制的有的定义。
  • 脏矩形本事。
  1. 二D绘制基础。
  2. 高级中学基本的三角函数 Sin,Cos。

功能图如下:

意义图如下:

比如您曾经主导领悟了上边提到到的知识点。OK。那接下去大家就一步一步落成那几个效果。

参照的稿子:

澳门葡京 5

澳门葡京 6

壹.环形渐变

唯恐大家都有影像,在Api德姆os中提供过二个事例仿照PS做的取色器效果。风乐趣的读者能够具体查看Api德姆os下的ColorPickerDialog的贯彻。那里我们参考她的写法,就足以做出一个轻松易行的环形渐变了。当然ColorPickerDialog中的主题代码也多亏利用了刚刚所提起的SweepGradient类用作渲染。该类属于Shader的子类,当然其兄弟类还有BitmapShader位图渲染、LinearGradient线性渲染、RadialGradient环形渲染、SweepGradient梯度渲染以及ComposeShader构成渲染。英特网有一大堆关于她们的牵线,能够做出过多很棒的意义。此处不实行。

主导代码如下:

private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);// 渐变色环画笔,抗锯齿private final int[] mColors = new int[] { 0xffff0000, 0xffffff00, 0xff00ff00,0xff00ffff,0xff0000ff,0xffff00ff };// 渐变色环颜色Shader s = new SweepGradient(0, 0, mColors, null);mPaint.setShader;mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeWidth;float r = CENTER_X - mPaint.getStrokeWidth() * 0.5f;canvas.save() ;canvas.translate(CENTER_X, CENTER_X);// 移动中心canvas.rotate;canvas.drawOval(new RectF(-r, -r, r, r), mPaint);// 画出色环和中心园canvas.restore();

效益如图1所示:

澳门葡京 7图1

代码批注:参考意义图上看,颜色是有藤黄潜移默化(并非线性渐变,这里大家先依照简约的贯彻)为石磨蓝,而且成效并非为多个整圆。为了总括方便,我们假若该圆环的角度为240度。如图二所示

澳门葡京 8图2大家已知SweepGradient是贰个360度均匀分布的渐变,大家一共设置了五个渐变色:从丁卯革命到稻草黄,使其均匀布满在圆环上。而绘制圆的时候,我们先将canvas的原点(在android2D图形系统中其坐标系原点在视图左上角)通过canvas.translate()移动至了圆环的中央点。在此我们应用canvas.rotate()旋转操作,旋转150度,使其青绿渐变的伊始地点处于图片左下方(此地准确的接头应该是这么:由于大家对画布旋转了150度,所以大家在绘制完圆环之后,通过restore()方法又使得画布回归到原来职位,从而达到了将革命渐变位于左下方的目标)。调治完canvas之后,大家通过canvas.drawOval()将圆绘制上去。最终将画布回归到原来的职分。此处还利用了canvas.save()canvas.restore()重组操作。简要介绍一下:由于那里大家对画布有移动、旋转操作。为了不形成对后续绘制的熏陶,使其复杂度扩充。大家接纳save()和restore()的组成来驱动画布回归到它原本的岗位。此举有时候会对品质爆发一定的熏陶,本文只是step
by
step的达成教程,而且此功用并不会强依赖于品质,所以品质在此地先放一边。文末作者会评释能够优化的点,供我们思索、探讨。在此处调用完restore()的表象正是canvas的原点又重回了视图的左上角。关于切实对canvas.save()canvas.restore()的阐述,网络有第一次全国代表大会堆。那里不详细打开。大概能够知道为save()为保存当前canvas状态,restore则为复原上2次save()的气象。

  1. Android自定义控件
    芝麻信用分雷达图

代码如下:

代码如下:

二.绘制内圆

着力代码如下

paintMiddleCircle.setColor(Color.GRAY);paintInnerCircle.setColor(Color.GRAY);paintMiddleCircle.setStrokeWidth;paintInnerCircle.setStrokeWidth;paintMiddleCircle.setStyle(Paint.Style.STROKE);paintInnerCircle.setStyle(Paint.Style.STROKE);PathEffect effects = new DashPathEffect(new float[]{5,5,5,5},1);paintInnerCircle.setPathEffect;canvas.save() ;canvas.translate(CENTER_X, CENTER_X);canvas.drawCircle(0, 0, CENTER_X * 5 / 8, paintInnerCircle);canvas.drawCircle(0, 0, CENTER_X * 3 / 4, paintMiddleCircle);canvas.restore();

作用如图三所示

澳门葡京 9图3

代码解说:该效率相比轻易。在那边须求领悟PathEffect及其子类的效应,那里大家运用DashPathEffect绘制虚线。细心的读者还能窥见,大家选择的绘图圆形的法子不平等。后边使用的是drawOval绘制椭圆,而在那边使用的是drawCircle直接画圆,效果都一样。具体分歧能够和煦体会,一个是框死了画内切椭圆,另2个是一直画圆。

此处为了爱护上边那篇文章的撰稿人,要求证美赞臣(Meadjohnson)下,上边包车型地铁代码有部分是参考下边这篇文章的。那里作者读书之后有了和谐的明亮。做了少数小改换,然后以相好的思绪来捋壹捋。希望自个儿的文字对你更有帮扶,哈哈。
(Pentagon –伍边形)

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script>
        function drawGraph(id)
        {
            var canvas=document.getElementById(id);
            var context=canvas.getContext("2d");
            context.fillStyle="#CC00FF"
            context.fillRect(0,0,300,300)
            context.beginPath()
            context.fillStyle="#008B8B"
            context.strokeStyle="#FFFF00"
            var dx=150
            var dy=150
            var s=100
            var dig=Math.PI/15*11
            context.moveTo(dx,dy)
            for(var i=0;i<60;i++)
            {
                var x=Math.sin(i*dig)
                var y=Math.cos(i*dig)
                context.bezierCurveTo(dx+x*s,dy+y*s-100,dx+x*s+100,dy+y*s,dx+x*s,dy+y*s)//贝塞尔绘制函数
            }
            context.closePath()
            context.fill()
            context.stroke()
        }
    </script>
</head>
<body onload="drawGraph('canvasId')">
<canvas id="canvasId" width="300" height="400"></canvas>
</body>
</html>
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script>
        function drawGraph(id)
        {
            var canvas=document.getElementById(id);
            var context=canvas.getContext("2d");
            context.fillStyle="#CC00FF"
            context.fillRect(0,0,300,300)
            context.beginPath()
            context.fillStyle="#008B8B"
            context.strokeStyle="#FFFF00"
            var dx=150
            var dy=150
            var s=100
            var dig=Math.PI/15*11
            context.moveTo(dx,dy)
            for(var i=0;i<60;i++)
            {
                var x=Math.sin(i*dig)
                var y=Math.cos(i*dig)
                context.bezierCurveTo(dx+x*s,dy+y*s-100,dx+x*s+100,dy+y*s,dx+x*s,dy+y*s)//贝塞尔绘制函数
            }
            context.closePath()
            context.fill()
            context.stroke()
        }
    </script>
</head>
<body onload="drawGraph('canvasId')">
<canvas id="canvasId" width="300" height="400"></canvas>
</body>
</html>

叁.绘制协理线

主干代码如下

paintGap1.setColor(Color.WHITE);paintGap2.setColor(Color.WHITE);paintGap1.setStrokeWidth;paintGap2.setStrokeWidth;int a =  (2 * CENTER_X - mPaint.getStrokeWidth;for ( int i=0;i<=60; i++) { canvas.save() ; canvas.rotate(-(-30 + 4 * i), CENTER_X, CENTER_X); if ( i % 10 == 0 ) { canvas.drawLine( a ,CENTER_X, 2 * CENTER_X, CENTER_X, paintGap2); } else { canvas.drawLine( a ,CENTER_X, 2 * CENTER_X, CENTER_X, paintGap1); } canvas.restore();}

成效如图4所示

澳门葡京 10图4

代码解说在地点,大家曾若是了圆弧的角度为240度。便于总计,大家将该圆弧划分为四个区,每种区占40度,每一个区有十个小间隔,各样小间隔的角度正是4度。由于圆弧有30度是在水平线以下的,所以大家的轮回规则是上述代码。canvas.rotate(-(-30 + 4 * i), CENTER_X, CENTER_X);此处由于CENTER_X==CENTER_Y==r,将上述代码修改为canvas.rotate(-(-30 + 4 * i), CENTER_X, CENTER_Y);莫不更易于精晓。rotate中参数>0为顺时针旋转,<0为逆时针旋转。

绘制思路:

 

 

四.圆环变圆弧

到近日截止,大家画的还只是个渐变圆环,与功力圆弧还有些区别。上边我们将圆环管理为圆弧。**
宗旨代码如下 **

width = MeasureSpec.getSize(widthMeasureSpec);height =  ( ( Math.tan(Math.PI / 6) + 1 ) * width / 2 ) ;Path path = new Path();path.moveTo(CENTER_X, CENTER_X);path.lineTo(0, height);path.lineTo(width, height);path.lineTo(CENTER_X, CENTER_X);path.close();canvas.drawPath(path, paintBg);

效果图5如下

澳门葡京 11图5**
代码解说:**先是大家须要调节视图的中度。在那此前我们都以令width==height,保障绘制出叁个整圆。将来依附大家的假诺圆弧度数240度,其在水平线以下为30度,即PI/6。由数学公式总括获知,其视图高度为
height = r * tan + r。那还不够,调解完视图的万丈,大家须求将部分杂线,从视图中除了,让其看起来更像是个圆弧。如图陆所示未去杂线的时候澳门葡京 12图6

我们使用图层相互遮罩的法则。以圆心和视图的多个终端,连接成三个三角形,能够直达掩盖其与杂线的目标。也正是后边代码的效果。记住在onDraw时候的三个口径:先画的在画布下方,后画的在画布上方,后画的会覆盖先画的。从而达到图5的效益。

  1. 算算四个5边形的七个顶峰的坐标,用 path 连接起来并绘制
  2. 算算要展现的多寡的多少个终端的坐标,用 path 连接起来并绘制
  3. 绘图五条射线
  4. 总结图标和标题的坐标地方,并绘制
  5. 绘制中间的分数

   
 关于领悟的html伍的主干知识点就到那里了,毕竟项目中一直不去行使,出于个人闲来无事有个大约领会.并且都很基本,其实那一个骨干的知识点感到没供给费用这么多精力去关怀,那几个时间个人以为花的太多,完全能够找个小demo去研商,那样驱动的去学习效果会越来越好,先到此地了,策动投入到下1阶段别的支付知识点的学习中.

   
 关于通晓的html5的着力知识点就到此处了,终归项目中平昔不去行使,出于个人闲来无事有个大致领会.并且都很基本,其实这一个骨干的知识点感觉没须求开支这么多精力去关爱,那些日子个人感到花的太多,完全能够找个小demo去商量,那样驱动的去学习效果会越来越好,先到那里了,准备投入到下一阶段别的开销知识点的求学中.

5.文字的绘图

** 大旨代码如下**

private static final String[] text = {"950","极好","700","优秀","650","良好","600","中等","550","较差","350","很差","150"};for ( int i=0;i<=12;i++) { canvas.save(); canvas.rotate(-(-120 + 20 * i ), CENTER_X, CENTER_X); canvas.drawText(text[i],CENTER_X - 20 ,CENTER_X * 3 / 16,paintText); canvas.restore();}

效果图7如下

澳门葡京 13图7

** 代码解说
**我们已知各种区为40度。从参考功效图上可以看到每隔20度就会有一段文字。大家驾驭在绘制文字的时候,都是从左往右写的。所以大家在旋转画布的时候,起先点要求在原来的底蕴上再加90度,即逆时针旋转120度,然后绘入文字。当然那段绘制的经过供给在绘制三角形之后,不然部分文字会被三角形的遮罩遮盖起来。

先是步:绘制多少个伍边形和深灰蓝5边形

澳门葡京 14

此处写图片描述

开首化成员变量

private int dataCount = 5;//多边形维度
private float radian = (float) (Math.PI * 2 / dataCount);//每个维度的角度
private float radius;//一条星射线的长度,即是发散的五条线白线
private int centerX;//中心坐标 Y
private int centerY;//中心坐标 X
private String[] titles = {"履约能力", "信用历史", "人脉关系", "行为偏好", "身份特质"};//标题
private int[] icos = {R.mipmap.ic_launcher, R.mipmap.ic_launcher, R.mipmap.ic_launcher, R.mipmap.ic_launcher, R.mipmap.ic_launcher};//五个维度的图标
private float[] data = {170, 180, 100, 170, 150};//五个维度的数据值
private float maxValue = 190;//每个维度的最大值
private Paint mPaintText;//绘制文字的画笔
private int radarMargin = 40;//
private int mAlpha;//白色五边形的透明度
private Path mPentagonPath;//记录白色五边形的路径
private Paint mPentagonPaint;//绘制白色五边形的画笔
private Path mDataPath;//记录红色五边形的路径
private Paint mDataPaint;//绘制红色五边形的画笔

构造方法中开头化的多少

private void init() {
    mPentagonPaint = new Paint();//初始化白色五边形的画笔
    mPentagonPaint.setAntiAlias(true);//
    mPentagonPaint.setStrokeWidth(5);//
    mPentagonPaint.setColor(Color.WHITE);//
    mPentagonPaint.setStyle(Paint.Style.FILL_AND_STROKE);//

    mDataPaint = new Paint();//初始化红色五边形的画笔
    mDataPaint.setAntiAlias(true);//
    mDataPaint.setStrokeWidth(10);//
    mDataPaint.setColor(Color.RED);//
    mDataPaint.setAlpha(150);//
    mDataPaint.setStyle(Paint.Style.STROKE);//

    mPaintText = new Paint();//初始化文字画笔
    mPaintText.setAntiAlias(true);//
    mPaintText.setTextSize(50);//
    mPaintText.setColor(Color.WHITE);//
    mPaintText.setStyle(Paint.Style.FILL);//

    mPentagonPath = new Path();//初始化白色五边形路径
    mDataPath = new Path();//初始化红色五边形路径
    radius = 80;//星射线的初始值,也是最小的五边形的一条星射线的长度(后期会递增)
    mAlpha = 150;//白色五边形的透明度(后期后递减)
}

开头化数据之后是经过 radius
的长短来测算伍边形两极分化的坐标值,前期通过转移 radius
的值,来落成计算多个酸性绿5边形的五个顶峰的值。那里给出一张图,支持精晓。通过图中的三个革命三角形就能够求出顶点的坐标了。

澳门葡京 15

此处写图片描述

**右上角的顶点为率先个点,顺时针总结,position 依次是 0,一,贰,3,肆
**

public Point getPoint(int position) {
    return getPoint(position, 0, 1);
}

// 参数:position:顶点的位置,radarMargin:边距,percent:星射线长度的百分比,用于计算红色五边形的顶点
public Point getPoint(int position, int radarMargin, float percent) {//以五边形的中心点为坐标原点
    int x = 0;
    int y = 0;
    switch (position) {
        case 0://第一象限,右上角顶点的坐标计算
            x = (int) (centerX + (radius + radarMargin) * Math.sin(radian) * percent);
            y = (int) (centerY - (radius + radarMargin) * Math.cos(radian) * percent);
            break;
        case 1://第四象限,右下角顶点的坐标计算
            x = (int) (centerX + (radius + radarMargin) * Math.sin(radian / 2) * percent);
            y = (int) (centerY + (radius + radarMargin) * Math.cos(radian / 2) * percent);
            break;
        case 2://第三象限,左下角顶点的坐标计算
            x = (int) (centerX - (radius + radarMargin) * Math.sin(radian / 2) * percent);
            y = (int) (centerY + (radius + radarMargin) * Math.cos(radian / 2) * percent);
            break;
        case 3://第二象限,左上角顶点的坐标计算
            x = (int) (centerX - (radius + radarMargin) * Math.sin(radian) * percent);
            y = (int) (centerY - (radius + radarMargin) * Math.cos(radian) * percent);
            break;
        case 4:// Y 轴正方向顶点的计算
            x = centerX;
            y = (int) (centerY - (radius + radarMargin) * percent);
            break;
    }
    return new Point(x, y);
}

基本功职业都做足了,那么就举办伍边形的绘图了

private void drawPentagon(Canvas canvas) {
    for (int j = 0; j < 3; j++) {//绘制三层白色五边形
        radius += 70;//每一层五边形的星射线增加 70 的长度
        mAlpha -= 30;//每一层五边形的透明度减少 30
        mPentagonPaint.setAlpha(mAlpha);
        for (int i = 0; i < dataCount; i++) {//绘制一层
            if (i == 0) {
                mPentagonPath.moveTo(getPoint(i).x, getPoint(i).y);
            } else {
                mPentagonPath.lineTo(getPoint(i).x, getPoint(i).y);
            }
        }
        mPentagonPath.close();
        canvas.drawPath(mPentagonPath, mPentagonPaint);
    }

    for (int i = 0; i < dataCount; i++) {//绘制红色五边形
        float percent = data[i] / maxValue;//数据值与最大值的百分比
        if (i == 0) {
            mDataPath.moveTo(getPoint(i, 0, percent).x, getPoint(i, 0, percent).y);//通过百分比计算出红色顶点的位置
        } else {
            mDataPath.lineTo(getPoint(i, 0, percent).x, getPoint(i, 0, percent).y);
        }
    }
    mDataPath.close();
    canvas.drawPath(mDataPath, mDataPaint);
}

6.聊起底的动作效果

if ( isSetReferValue ) { float r1 = CENTER_X * 6 / 8 ; canvas.save(); canvas.translate(CENTER_X, CENTER_X); canvas.drawArc(new RectF(-r1, -r1, r1, r1), -210, currentRotateAngle, false, paintMiddleArc); canvas.rotate( - 30 + currentRotateAngle ); Matrix matrix = new Matrix(); matrix.preTranslate(-r1 - bitmapWidth * 3/ 8,-bitmapHeight/2); canvas.drawBitmap(bitmapLocation,matrix,paintBitmap); canvas.restore();}public void setReferValue ( int referValue ,final RotateListener rotateListener) { isSetReferValue = !isSetReferValue ; if ( referValue <= 150 ) { totalRotateAngle = 0f ; } else if ( referValue <= 550 ) { totalRotateAngle = ( referValue - 150 ) * 80 / 400f ; } else if ( referValue <= 700 ) { totalRotateAngle = ( referValue - 550 ) * 120 / 150f + 80 ; } else if ( referValue <= 950 ) { totalRotateAngle = ( referValue - 700 ) * 40 / 250f + 200; } else { totalRotateAngle = 210f ; } rotateAngle = totalRotateAngle / 60 ; new Thread(new Runnable() { @Override public void run() { boolean rotating = true ; float value = 350; while  { try { Thread.sleep; } catch (InterruptedException e) { e.printStackTrace(); } currentRotateAngle += rotateAngle; if ( currentRotateAngle >= totalRotateAngle ) { currentRotateAngle = totalRotateAngle; rotating = false; } if ( null != rotateListener) { if ( currentRotateAngle <= 80 ) { value = 350 + ( currentRotateAngle / 80 ) * 400 ; } else if ( currentRotateAngle <= 200 ) { value = 550 + ( ( currentRotateAngle - 80 )/ 120 ) * 150 ; } else { value = 700 + ( ( currentRotateAngle - 200 ) / 40 ) * 250 ; } rotateListener.rotate(currentRotateAngle,value); } postInvalidate.start(); }

效果图8如下

澳门葡京 16图8

代码批注制图的代码中。首先我们要询问到绘制圆弧的格局为canvas.drawArc(),此处大家要从左下角开端绘制圆弧,所以我们的胚胎旋转角度为-2拾度。由于我们那里的原点在圆心。图片要跟随着已知的团团转角度张开旋转。大家知道针对canvas.rotate()措施,当旋转角度>0的时候,是顺时针旋转;<0为逆时针转动。由于此处我们图片的箭头朝向向右,为了保证图片的通往指向圆心。我们旋转的平整为- 30 + currentRotateAngle,保障每3回在绘制图形的时候,都以在为(-r一

  • bitmapWidth * 3/
    八,-bitmapHeight/二)那个职位的时候绘制。最终恢复生机canvas。关于在总计totalRotateAnglecurrentRotateAngle以及
    value的时候,都以些轻松的算法。夹杂着多数硬编码,耐心点应该能够读懂,不做过多解释。

兑现的77捌8,差不离思路应该是那样。

第1步:绘制5条星射线

先来探望这一步的意义图:

澳门葡京 17

此间写图片描述

绘图好伍边形之后 radius 的值已经为最大伍边形的星射线的长短了。

private void drawFiveLine(Canvas canvas) {
    mPentagonPaint.setColor(Color.WHITE);//设置颜色为白色
    mPentagonPaint.setStrokeWidth(2);//设置宽度为2
    for (int i = 0; i < dataCount; i++) {
        canvas.drawLine(centerX, centerY, getPoint(i).x, getPoint(i).y, mPentagonPaint);//绘制
    }
}

某个标题

  1. 在上文也涉及了,参考的效劳图,并非是多个平坦的渐变。仔细观看的话,在600处有处弹指断的征象。化解思路:利用方面讲到过的波特DuffXfermode,将两段差别的环形渐变,拼接而成。达到此效用。
  2. 至于优化
  • onDraw()方法中,canvas.save()与canvas.restore()方法数次行使,变成不供给的属性浪费。
  • 在推行箭头转动作效果果的时候,不须求在canvas上每一趟全部都再也绘制。只须要绘制供给绘制的某些区域就能够,即脏矩形。在那边也正是箭头所滚动范围内的有的区域圆环。读者能够自动落成。
  1. 关于拾2线程细心的人能够开采方法setReferValue(),并未设想八线程的动静。此处只是demo,场景也轻松。没做特殊管理。有意思味的读者可以自动落成。

其三步:绘制七个标题

先来探望这一步的效果图:

澳门葡京 18

此地写图片描述

在这一步,相对难一些的便是坐标的猜度了。第1个顶峰的坐标经过加多radarMargin
值之后就足以一贯利用了,其余顶点还索要通过测算获得。那里其实正是要计算每1个Title 文字左下角的坐标。那么合算坐标的代码是那样的:

private void drawTitle(Canvas canvas) {
    for (int i = 0; i < dataCount; i++) {
        int x = getPoint(i, radarMargin, 1).x;//获取添加 radarMargin 值之后的 X 坐标的指
        int y = getPoint(i, radarMargin, 1).y;//获取添加 radarMargin 值之后的 Y 坐标的指
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), icos[i]);
        int iconHeight = bitmap.getHeight();
        int titleWidth = (int) mPaintText.measureText(titles[i]);
        switch (i) {
            case 1://说明一下为什么是 iconHeight / 2 ,主要是因为这样会比较好看
                y += iconHeight / 2;
                break;
            case 2:
                x -= titleWidth;
                y += iconHeight / 2;
                break;
            case 3:
                x -= titleWidth;
                break;
            case 4:
                x -= titleWidth / 2;
                break;
        }
        canvas.drawText(titles[i], x, y, mPaintText);
    }
}

后记

事先一向未有记录博客的习贯。未来写完两篇,开采将代码翻译成文不是壹件轻易的事。代码在周日将宗旨做到了,文章也是一贯拖着到现行反革命才整理出来发布。要将每一个知识点,能够简单来说明出来,是比较难的一件专门的工作。落笔成文同面对面与人描述,会不太一致。现在要多升高那方面包车型大巴演练。也期望读者们可以联手来尝试记录。遗留的主题素材,都不是很难,读者能够活动尝试的去得以落成。后天头脑有点疼,就写到此了。

源代码在此下载:

enjoy it!

想登时了然最新消息。扫1扫,增添关心微信公众号

澳门葡京 19weixin.jpg

初稿地址:

第四步:绘制Logo

先来探望这一步的职能:

澳门葡京 20

那边写图片描述

这一步也是要拓展坐标的测度,首要的揣测出放置Logo左上角的坐标值。这里照旧相对简单一点,不必要动用三角函数。

private void drawIcon(Canvas canvas) {
    for (int i = 0; i < dataCount; i++) {
        int x = getPoint(i, radarMargin, 1).x;//获取添加 radarMargin 值之后的 X 坐标的指
        int y = getPoint(i, radarMargin, 1).y;//获取添加 radarMargin 值之后的 Y 坐标的指
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), icos[i]);
        int iconHeight = bitmap.getHeight();
        int iconWidth = bitmap.getWidth();
        int titleWidth = (int) mPaintText.measureText(titles[i]);
        switch (i) {
            case 0:
                x += (titleWidth - iconWidth) / 2;
                y -= (iconHeight + getTextHeight(titles[i]));
                break;
            case 1:
                x += (titleWidth - iconWidth) / 2;
                y -= (iconHeight / 2 + getTextHeight(titles[i]));
                break;
            case 2:
                x -= titleWidth - (titleWidth - iconWidth) / 2;
                y -= (iconHeight / 2 + getTextHeight(titles[i]));
                break;
            case 3:
                x -= titleWidth - (titleWidth - iconWidth) / 2;
                y -= (iconHeight + getTextHeight(titles[i]));
                break;
            case 4:
                x -= (iconHeight / 2);
                y -= (iconHeight + getTextHeight(titles[i]));
                break;
        }
        canvas.drawBitmap(bitmap, x, y, mPaintText);
    }
}

第肆步:绘制核心点的分数

这一步成功之后就足以博得最终效果了,便是图1的职能:

澳门葡京 21

此地写图片描述

文字的坐标是骨干点,那么合算出文字的上涨的幅度和可观就能够从中呈现文字了。

private void drawScore(Canvas canvas) {
    mPaintText.setColor(getResources().getColor(R.color.colorAccent));
    int score = 0;
    for (int i = 0; i < data.length; i++) {//累加分数值
        score += data[i];
    }
    String str_score = String.valueOf(score);
    Paint.FontMetrics fm = mPaintText.getFontMetrics();//用于计算文字的高度
    canvas.drawText(str_score, centerX - mPaintText.measureText(str_score) / 2, (centerY + (int) Math.ceil(fm.descent - fm.ascent) / 2), mPaintText);
}

总结

一步步下来,对自定义 view 也有了更为的领会。觉得要求越来越多的练习才能一心
hold
住。若是文中有哪些知识点是谬误的可能更加好的贯彻方式,请及时调换本人实行改造,以防误导别人。谢谢。那么完整的代码是那样的。

/**
 * Created by zone on 2017/4/9.
 */

public class PentagonView extends View {
    private int dataCount = 5;//多边形维度,这里是五边形
    private float radian = (float) (Math.PI * 2 / dataCount);//每个维度的角度
    private float radius;//一条星射线的长度,即是发散的五条线白线
    private int centerX;//中心坐标 Y
    private int centerY;//中心坐标 X
    private String[] titles = {"履约能力", "信用历史", "人脉关系", "行为偏好", "身份特质"};//标题
    private int[] icos = {R.mipmap.ic_launcher, R.mipmap.ic_launcher, R.mipmap.ic_launcher, R.mipmap.ic_launcher, R.mipmap.ic_launcher};//五个维度的图标
    private float[] data = {170, 180, 100, 170, 150};//五个维度的数据值
    private float maxValue = 190;//每个维度的最大值
    private Paint mPaintText;//绘制文字的画笔
    private int radarMargin = 40;//
    private int mAlpha;//白色五边形的透明度
    private Path mPentagonPath;//记录白色五边形的路径
    private Paint mPentagonPaint;//绘制白色五边形的画笔
    private Path mDataPath;//记录红色五边形的路径
    private Paint mDataPaint;//绘制红色五边形的画笔


    public PentagonView(Context context) {
        super(context);
        init();
    }

    public PentagonView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public PentagonView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public PentagonView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init() {
        mPentagonPaint = new Paint();//初始化白色五边形的画笔
        mPentagonPaint.setAntiAlias(true);//
        mPentagonPaint.setStrokeWidth(5);//
        mPentagonPaint.setColor(Color.WHITE);//
        mPentagonPaint.setStyle(Paint.Style.FILL_AND_STROKE);//

        mDataPaint = new Paint();//初始化红色五边形的画笔
        mDataPaint.setAntiAlias(true);//
        mDataPaint.setStrokeWidth(10);//
        mDataPaint.setColor(Color.RED);//
        mDataPaint.setAlpha(150);//
        mDataPaint.setStyle(Paint.Style.STROKE);//

        mPaintText = new Paint();//初始化文字画笔
        mPaintText.setAntiAlias(true);//
        mPaintText.setTextSize(50);//
        mPaintText.setColor(Color.WHITE);//
        mPaintText.setStyle(Paint.Style.FILL);//

        mPentagonPath = new Path();//初始化白色五边形路径
        mDataPath = new Path();//初始化红色五边形路径
        radius = 80;//星射线的初始值,也是最小的五边形的一条星射线的长度(后期会递增)
        mAlpha = 150;//白色五边形的透明度(后期后递减)
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(getResources().getColor(R.color.colorAccent));
        centerX = getWidth() / 2;
        centerY = getHeight() / 2;
        drawPentagon(canvas);//绘制白色五边形和红色五边形
        drawFiveLine(canvas);//绘制五条星射线
        drawTitle(canvas);//绘制五个标题
        drawIcon(canvas);//绘制五个图标
        drawScore(canvas);//绘制中间的分数
    }

    private void drawPentagon(Canvas canvas) {
        for (int j = 0; j < 3; j++) {//绘制三层白色五边形
            radius += 70;//每一层五边形的星射线增加 70 的长度
            mAlpha -= 30;//每一层五边形的透明度减少 30
            mPentagonPaint.setAlpha(mAlpha);
            for (int i = 0; i < dataCount; i++) {//绘制一层
                if (i == 0) {
                    mPentagonPath.moveTo(getPoint(i).x, getPoint(i).y);
                } else {
                    mPentagonPath.lineTo(getPoint(i).x, getPoint(i).y);
                }
            }
            mPentagonPath.close();
            canvas.drawPath(mPentagonPath, mPentagonPaint);
        }

        for (int i = 0; i < dataCount; i++) {//绘制红色五边形
            float percent = data[i] / maxValue;//数据值与最大值的百分比
            if (i == 0) {
                mDataPath.moveTo(getPoint(i, 0, percent).x, getPoint(i, 0, percent).y);//通过百分比计算出红色顶点的位置
            } else {
                mDataPath.lineTo(getPoint(i, 0, percent).x, getPoint(i, 0, percent).y);
            }
        }
        mDataPath.close();
        canvas.drawPath(mDataPath, mDataPaint);
    }

    private void drawFiveLine(Canvas canvas) {
        mPentagonPaint.setColor(Color.WHITE);//设置颜色为白色
        mPentagonPaint.setStrokeWidth(2);//设置宽度为2
        for (int i = 0; i < dataCount; i++) {
            canvas.drawLine(centerX, centerY, getPoint(i).x, getPoint(i).y, mPentagonPaint);//绘制
        }
    }

    private void drawIcon(Canvas canvas) {
        for (int i = 0; i < dataCount; i++) {
            int x = getPoint(i, radarMargin, 1).x;//获取添加 radarMargin 值之后的 X 坐标的指
            int y = getPoint(i, radarMargin, 1).y;//获取添加 radarMargin 值之后的 Y 坐标的指
            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), icos[i]);
            int iconHeight = bitmap.getHeight();
            int iconWidth = bitmap.getWidth();
            int titleWidth = (int) mPaintText.measureText(titles[i]);
            switch (i) {
                case 0:
                    x += (titleWidth - iconWidth) / 2;
                    y -= (iconHeight + getTextHeight(titles[i]));
                    break;
                case 1:
                    x += (titleWidth - iconWidth) / 2;
                    y -= (iconHeight / 2 + getTextHeight(titles[i]));
                    break;
                case 2:
                    x -= titleWidth - (titleWidth - iconWidth) / 2;
                    y -= (iconHeight / 2 + getTextHeight(titles[i]));
                    break;
                case 3:
                    x -= titleWidth - (titleWidth - iconWidth) / 2;
                    y -= (iconHeight + getTextHeight(titles[i]));
                    break;
                case 4:
                    x -= (iconHeight / 2);
                    y -= (iconHeight + getTextHeight(titles[i]));
                    break;
            }
            canvas.drawBitmap(bitmap, x, y, mPaintText);
        }
    }

    private int getTextHeight(String text) {
        Paint.FontMetrics fm = mPaintText.getFontMetrics();
        return (int) Math.ceil(fm.descent - fm.ascent);
    }

    private void drawTitle(Canvas canvas) {
        for (int i = 0; i < dataCount; i++) {
            int x = getPoint(i, radarMargin, 1).x;//获取添加 radarMargin 值之后的 X 坐标的指
            int y = getPoint(i, radarMargin, 1).y;//获取添加 radarMargin 值之后的 Y 坐标的指
            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), icos[i]);
            int iconHeight = bitmap.getHeight();
            int titleWidth = (int) mPaintText.measureText(titles[i]);
            switch (i) {
                case 1://说明一下为什么是 iconHeight / 2 ,主要是因为这样会比较好看
                    y += iconHeight / 2;
                    break;
                case 2:
                    x -= titleWidth;
                    y += iconHeight / 2;
                    break;
                case 3:
                    x -= titleWidth;
                    break;
                case 4:
                    x -= titleWidth / 2;
                    break;
            }
            canvas.drawText(titles[i], x, y, mPaintText);
        }
    }

    private void drawScore(Canvas canvas) {
        mPaintText.setColor(getResources().getColor(R.color.colorAccent));
        int score = 0;
        for (int i = 0; i < data.length; i++) {//累加分数值
            score += data[i];
        }
        String str_score = String.valueOf(score);
        Paint.FontMetrics fm = mPaintText.getFontMetrics();//用于计算文字的高度
        canvas.drawText(str_score, centerX - mPaintText.measureText(str_score) / 2, (centerY + (int) Math.ceil(fm.descent - fm.ascent) / 2), mPaintText);
    }

    public Point getPoint(int position) {
        return getPoint(position, 0, 1);
    }

// 右上角的顶点为第一个点,顺时针计算,position 依次是 0,1,2,3,4
// 参数:position:顶点的位置,radarMargin:边距,percent:星射线长度的百分比,用于计算红色五边形的顶点
    public Point getPoint(int position, int radarMargin, float percent) {//以五边形的中心点为坐标原点
        int x = 0;
        int y = 0;
        switch (position) {
            case 0://第一象限,右上角顶点的坐标计算
                x = (int) (centerX + (radius + radarMargin) * Math.sin(radian) * percent);
                y = (int) (centerY - (radius + radarMargin) * Math.cos(radian) * percent);
                break;
            case 1://第四象限,右下角顶点的坐标计算
                x = (int) (centerX + (radius + radarMargin) * Math.sin(radian / 2) * percent);
                y = (int) (centerY + (radius + radarMargin) * Math.cos(radian / 2) * percent);
                break;
            case 2://第三象限,左下角顶点的坐标计算
                x = (int) (centerX - (radius + radarMargin) * Math.sin(radian / 2) * percent);
                y = (int) (centerY + (radius + radarMargin) * Math.cos(radian / 2) * percent);
                break;
            case 3://第二象限,左上角顶点的坐标计算
                x = (int) (centerX - (radius + radarMargin) * Math.sin(radian) * percent);
                y = (int) (centerY - (radius + radarMargin) * Math.cos(radian) * percent);
                break;
            case 4:// Y 轴正方向顶点的计算
                x = centerX;
                y = (int) (centerY - (radius + radarMargin) * percent);
                break;
        }
        return new Point(x, y);
    }
}

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website