html5读书笔记6,一步一步教你什么样贯彻Ali芝麻

2019-05-03 22:39 来源:未知

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

原文地址:

韦德娱乐1946网页版 1

废话不多说,先看下效果:

实现代码如下:

韦德娱乐1946网页版 2参考效果图

<!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有一定的了解。先对涉及到的知识点罗列如下,还不是很了解的读者可以先自行百度做个简单的涉猎,对后续文章的理解会有很大帮助。

 绘制贝塞尔曲线

  • Paint、Canvas这两个基础的类必须熟悉。
  • 用作渲染的Shader类及其子类,以及后文中使用的是SweepGradient梯度渲染,用作渐变圆环,需要了解。
  • canvas.save() & canvas.restore() 的作用与关系。
  • 由Paint引申的PathEffect、PorterDuffXfermode,已经Matrix等类要有个基本的概念。
  • 图层绘制的一些概念。
  • 脏矩形技术。

效果图如下:

如果你已经基本了解了上面涉及到的知识点。OK。那接下来我们就一步一步实现这个效果。

韦德娱乐1946网页版 3

1.环形渐变

或许大家都有印象,在ApiDemos中提供过一个例子仿照PS做的取色器效果。有兴趣的读者可以具体查看ApiDemos下的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所示:

韦德娱乐1946网页版 4图1

代码讲解:参考效果图上看,颜色是有红色渐变(并非线性渐变,这里我们先按照简单的实现)为绿色,而且效果并非为一个整圆。为了计算方便,我们假设该圆环的角度为240度。如图2所示

韦德娱乐1946网页版 5图2我们已知SweepGradient是一个360度均匀分布的渐变,我们一共设置了6个渐变色:从红色到紫色,使其均匀分布在圆环上。而绘制圆的时候,我们先将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则为恢复上一次save()的状态。

代码如下:

2.绘制内圆

核心代码如下

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();

效果如图3所示

韦德娱乐1946网页版 6图3

代码讲解:该功能比较简单。在此处需要了解PathEffect及其子类的作用,这里我们使用DashPathEffect绘制虚线。细心的读者还可以发现,我们使用的绘制圆形的方法不一样。前面使用的是drawOval绘制椭圆,而在此处使用的是drawCircle直接画圆,效果都一样。具体区别可以自己体会,一个是框死了画内切椭圆,另一个是直接画圆。

<!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>

3.绘制辅助线

核心代码如下

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所示

韦德娱乐1946网页版 7图4

代码讲解在上面,我们曾假设了圆弧的角度为240度。便于计算,我们将该圆弧划分为6个区,每个区占40度,每个区有10个小间隔,每个小间隔的角度就是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为逆时针旋转。

 

4.圆环变圆弧

到目前为止,我们画的还只是个渐变圆环,与效果圆弧还有些不同。下面我们将圆环处理为圆弧。** 核心代码如下 **

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如下

韦德娱乐1946网页版 8图5** 代码讲解:**首先我们需要调整视图的高度。在这之前我们都是令width==height,保证绘制出一个整圆。现在根据我们的假设圆弧度数240度,其在水平线以下为30度,即PI/6。由数学公式计算得知,其视图高度为 height = r * tan r。这还不够,调整完视图的高度,我们需要将一些杂线,从视图中除去,让其看上去更像是个圆弧。如图6所示未去杂线的时候韦德娱乐1946网页版 9图6

我们利用图层互相遮罩的原理。以圆心和视图的两个顶点,连接成一个三角形,可以达到掩盖其与杂线的目的。也就是后面代码的作用。记住在onDraw时候的一个原则:先画的在画布下方,后画的在画布上方,后画的会覆盖先画的。从而达到图5的效果。

     关于了解的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如下

韦德娱乐1946网页版 10图7

** 代码讲解 **我们已知每个区为40度。从参考效果图上可以看出每隔20度就会有一段文字。我们知道在绘制文字的时候,都是从左往右写的。所以我们在旋转画布的时候,起始点需要在原来的基础上再加90度,即逆时针旋转120度,然后绘入文字。当然这段绘制的过程需要在绘制三角形之后,否则部分文字会被三角形的遮罩遮盖起来。

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如下

韦德娱乐1946网页版 11图8

代码讲解绘制的代码中。首先我们要了解到绘制圆弧的方法为canvas.drawArc(),此处我们要从左下角开始绘制圆弧,所以我们的起始旋转角度为-210度。由于我们此处的原点在圆心。图片要跟随着已知的旋转角度进行旋转。我们知道针对canvas.rotate()方法,当旋转角度>0的时候,是顺时针旋转;<0为逆时针旋转。由于此处我们图片的箭头朝向向右,为了保证图片的朝向指向圆心。我们旋转的规则为- 30 currentRotateAngle,保证每一次在绘制图形的时候,都是在为(-r1

  • bitmapWidth * 3/ 8,-bitmapHeight/2)这个位置的时候绘制。最后恢复canvas。关于在计算totalRotateAnglecurrentRotateAngle以及 value的时候,都是些简单的算法。夹杂着很多硬编码,耐心点应该可以读懂,不做过多解释。

实现的七七八八,大致思路应该是这样。

一些问题

  1. 在上文也提到了,参考的效果图,并非是一个平滑的渐变。仔细观察的话,在600处有处瞬断的迹象。解决思路:利用上面讲到过的PorterDuffXfermode,将两段不同的环形渐变,拼接而成。到达此效果。
  2. 关于优化
  • onDraw()方法中,canvas.save()与canvas.restore()方法多次使用,造成不必要的性能浪费。
  • 在执行箭头转动效果的时候,不需要在canvas上每次全部都重新绘制。只需要绘制需要绘制的部分区域即可,即脏矩形。在这里也就是箭头所滚动范围内的部分区域圆环。读者可以自行实现。
  1. 关于多线程细心的人可以发现方法setReferValue(),并没有考虑多线程的情况。此处只是demo,场景也有限。没做特殊处理。有兴趣的读者可以自行实现。

后记

之前一直没有记录博客的习惯。现在写完两篇,发现将代码翻译成文不是一件容易的事。代码在周三就基本完成了,文章也是一直拖着到现在才整理出来发布。要将每一个知识点,能够简单的表述出来,是比较难的一件事情。落笔成文同面对面与人讲述,会不太一样。以后要多加强这方面的练习。也希望读者们能够一起来尝试记录。遗留的问题,都不是很难,读者可以自行尝试的去实现。今天脑子有点疼,就写到此了。

源代码在此下载:

enjoy it!

想及时了解最新信息。扫一扫,添加关注微信公众号

韦德娱乐1946网页版 12weixin.jpg

原文地址:

TAG标签: 韦德娱乐1946
版权声明:本文由韦德娱乐1946_韦德娱乐1946网页版|韦德国际1946官网发布于韦德娱乐1946网页版,转载请注明出处:html5读书笔记6,一步一步教你什么样贯彻Ali芝麻