一、前言

 

上节 通过一个简单的旋转环对自定义view作了一个基本的认识,本文将大致讲解下实现的思路以及对该view的一些可能的改进。

 

二、思路

 

主要通过重写 view 中的 onDraw() 方法,利用 canvas 类中的 drawArc() 方法绘制圆弧,其中第一个参数 rectF 是一个浮点矩形,确定了圆弧的大小及位置 (想象一个放在矩形中的圆,截取其弧即成圆环)。其中圆弧颜色由画笔类 Paint 定义, 为简单起见,这里使用两种颜色的渐变色。值得一提的是,当圆弧两端成圆头时 ( paint.getStrokeCap() == Paint.Cap.ROUND ),其首端的圆头颜色为尾部的颜色,如图2.1.1 所示。因此此处要将起始旋转角度 + width/2。其中 width 为圆环的宽度,除以2 恰好为圆头的半径,故可以通过这种办法消除掉,如图2.1.2所示

 

绘制圆弧需要确定起始角度 startAngle,以及扫过的角度sweepAngle,对于 startAngle,其中3点钟方向为0°, sweepAngle一般不超过360° (超过即成一个完整的圆)。此外还需要一个boolean变量的值,来确定是否绘出圆弧对应的半径。由于我们不需要扇形,这里设为fasle。

 

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.rotate(angle, centerX, centerY);
        canvas.drawArc(rectF, paint.getStrokeCap() == Paint.Cap.ROUND ? startAngle + width/2f: startAngle,
                sweepAngle, false, paint);
    }

 

         

 图2.1.1  首部圆头部分出现尾部颜色                      图2.1.2   正常的圆弧

 

canvas.drawArc() 的第五个参数为Paint类型,这里定义了绘制圆弧所用到的画笔,如下所示

 

private void setPaint(){
        paint = new Paint();
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setShader(new SweepGradient(centerX, centerY,
                new int[]{startColor, endColor},
                new float[]{startAngle/360f*1.0f, sweepAngle/360f*1.0f}));
        paint.setAntiAlias(true);
        paint.setStrokeWidth(width);
    }

  

此处主要说说何处初始化该 paint 的原因。由于实现圆弧的渐变色用到了 SweepGradient 着色器,着色器需要传入x、y来确定扫描渐变色的中心,故需要在获取到控件中心之后再进行初始化。在该自定义圆弧控件中,是通过 onSizeChanged(int w, int h, int oldw, int oldh) 方法来获取控件视图的中点,故在 onSizeChanged() 方法中对画笔进行初始化,如下所示

 

@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        centerX = w / 2;
        centerY = h / 2;
        rectF = new RectF(centerX - radius, centerY - radius, centerX + radius, centerY + radius);
        setPaint();
    }

  

最后,通过 ValueAnimator 类给圆弧设置一个旋转动画,通过调用视图本身的 invalidate() 方法,不断通知视图进行重绘 (不断调用onDraw()方法 ),实现了圆弧视觉上的旋转。

 

public void startAnim(){
        final ValueAnimator animator = ValueAnimator.ofInt(0,360);
        animator.setDuration(duration);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setRepeatMode(ValueAnimator.RESTART);
        animator.setInterpolator(new LinearInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                angle = (int) animation.getAnimatedValue();
                invalidate();
            }
        });
        animator.start();
    }

  

下节 讲述如何添加自定义属性,在xml中声明旋转环的颜色、半径、宽度,旋转速率等,避免在代码中显式调用setXXX()方法。

 posted on 2020-05-12 16:18  蓝天的抛物线  阅读(240)  评论(0编辑  收藏  举报