Android 自定义-充电View(一)

       之前搞完了基础的自定义中的 canvas,paint,那么就来试一下吧。

Android 自定义-充电View(一)_第1张图片
充电.jpg

       好了来试一下这个View 是怎么实现的,今天先不搞动画之类的,只是做对前知识的复习,这个图分成两块,上面是三个圆弧加一个圆,然后内部有个Text,下面有个曲线,然后一直画到下面的直线,那就是三个方法 canvas.drawCircle(),canvas.drawArc(),canvas.drawText(),canvas.drawLine();
首先画圆弧7(其实这里并不是7点方向不是很严谨,应该是120°,只说个7点大概位置大伙知道就好)点方向顺时针到5点方向, canvas.drawArc(rectF,120,300,false,outPaint),通过改变rectF的大小来实现三个外圈的实现,再通过paint.setAlpha(0-255)来实现逐渐透明。最后画个圆,中间写上Text,写文字涉及到基线的问题,这里贴上代码:

      Rect rect = new Rect(getWidth()/2-150,getHeight()/2-150,getWidth()/2+150,getHeight()/2+150);//画一个矩形
    Paint textPaint = new Paint();
    textPaint.setColor(Color.WHITE);
    textPaint.setTextSize(100);
    textPaint.setStyle(Paint.Style.FILL);
    //该方法即为设置基线上那个点究竟是left,center,还是right  这里我设置为center
    textPaint.setTextAlign(Paint.Align.CENTER);
    Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
    float top = fontMetrics.top;
    float bottom = fontMetrics.bottom;bottom
    int baseLineY = (int) (rect.centerY() - top/2 - bottom/2);
    canvas.drawText("90%",rect.centerX(),baseLineY,textPaint);

然后画出弧线,再接上一个直线,弧线这里先用贝塞尔的思想,直接写上代码实现弧线的操作,关于贝塞尔等以后写博客的时候再介绍。

    Path path = new Path();
    path.moveTo(x,y);//这里的x,y为出发点的坐标。
    path.quadTo(x1,y1,x2,y2);//这里的x1,y1 就是参照点,x2,y2就是终点。先mark。

最后通过drawLine来实现几个竖直的线,至于动画这里先不研究。好了看上去思路在这了,我们来看看实际的效果,首先这个充电的View有个颜色的渐变,如何实现这个颜色的渐变,之前只知道Paint.setColor这个方法而且设置的也是一个颜色。下面有两个思路:

  1. 画圆的时候一个弧一个弧的画,通过不停的改变画笔的颜色来实现,很明显这个太坑了,根本做不动,毕竟人家的颜色还是渐变的。

  2. 能否找到像shape一类的操作来实现颜色的渐变:百度一下一看,哎嘿有个Shader类,其中这里使用到的是SweepGradient,这个东西有一些坑,这个类内容很少,可以通过注释了解这个函数的大概,有两种方法(1)
    SweepGradient(float cx, float cy, @ColorInt int color0, @ColorInt int color1)这个方法其实就是坐标中心x,y,然后一个startColor,一个endColor。实现渐变。
    (2)SweepGradient(float cx, float cy,
    @NonNull @ColorInt int colors[], @Nullable float positions[])
    这个方法就有意思了,colors[]表示是要填充的颜色,position表示每个颜色占的比重,为0-1。为null时候,系统自动给颜色进行均匀分布,比如colors里面有三个元素,为null他自己会均匀的分布,你也可以设置position这个就可以实现每个元素占的比重,比如float{0,0.5,1}那么这三个颜色就是从0(也就是开始的地方),然后到一半(0.5)实现的是第一个颜色到第二个颜色的渐变,(0.5-1)实现的是第二个颜色到第三个颜色的渐变。如下代码:

    float[] ff1  = new float[3];
     ff1[0] = 0;
     ff1[1] = (float) (0.5);
     ff1[2] = (float)(1);
     colors = new int[]{0xFFE61AE6,Color.BLUE,Color.RED};
     sweepGradient0 = new SweepGradient(getWidth()/2, getHeight()/2,colors,ff1);
     innerPaint.setShader(sweepGradient0);
     canvas.drawCircle(getWidth()/2,getHeight()/2,150,innerPaint);
    

Android 自定义-充电View(一)_第2张图片
position参数.png

       注意这里画圆的时候所有的画笔开始的地方都是从3点方向开始的,这样就能看出{0,0.5,1}的区分了,具体可以再尝试做实验。
好了问题又来了我们可以直接画弧形从7点开始画,但是用 SweepGradient的时候发现这玩意并没有跟着画笔走,而是还是从三点方向开始往下,那这样跟我们的预期肯定不符合啊,我们得让他跟着画笔的开始走,这时候就要用到一个新的类 Matrix这里看一下使用方法:

    Matrix matrix = new Matrix();
    matrix.setRotate(120,getWidth()/2,getHeight()/2);
    sweepGradient0.setLocalMatrix(matrix);

这样就可以实现颜色也从7点方法开始画了。附上完整代码:

public class ChargeView extends View {
      Paint outPaint,innerPaint,textPaint;
      int startColor;
      int midColor;
      int endColor;
      private int[] colors;
      String TAG = "ChargeView";
      float PADDING = 20;

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

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

      public ChargeView(Context context,AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
          TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.ChargeView);
          startColor = typedArray.getColor(R.styleable.ChargeView_start_color,Color.RED);
          midColor = typedArray.getColor(R.styleable.ChargeView_middle_color,Color.GREEN);
          endColor = typedArray.getColor(R.styleable.ChargeView_end_color,Color.BLUE);
          typedArray.recycle();
          initView();
      }

      private void initView(){
          outPaint = new Paint();
          innerPaint = new Paint();
          textPaint = new Paint();
          outPaint.setStyle(Paint.Style.STROKE);
          innerPaint.setStyle(Paint.Style.STROKE);
          outPaint.setAntiAlias(true);
          innerPaint.setAntiAlias(true);
          textPaint.setAntiAlias(true);
          outPaint.setStrokeWidth(2);
          innerPaint.setStrokeWidth(30);
          textPaint.setTextSize(15);
          SweepGradient sweepGradient;
          colors = new int[]{Color.BLUE,startColor,Color.BLUE};

      }

      @Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
          super.onMeasure(widthMeasureSpec, heightMeasureSpec);
          setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),MeasureSpec.getSize(heightMeasureSpec));
      }


      @Override
      protected void onDraw(Canvas canvas) {
          super.onDraw(canvas);

          SweepGradient sweepGradient0;
          Matrix matrix = new Matrix();
          matrix.setRotate(120,getWidth()/2,getHeight()/2);
          Log.e(TAG, "onDraw: " );
          float[] ff  = new float[3];
          ff[0] = 0;
          ff[1] = (float) (5/12.0);
          Log.e("TAG",(float) (5/12.0)+"");
          ff[2] = (float)(5/6.0);

          sweepGradient0 = new SweepGradient(getWidth()/2, getHeight()/2,colors,ff);
          sweepGradient0.setLocalMatrix(matrix);
          outPaint.setShader(sweepGradient0);
          drawCircle(canvas,200);
          outPaint.setAlpha(150);
          drawCircle(canvas,190);
          outPaint.setAlpha(50);
          drawCircle(canvas,180);

          colors = new int[]{0xFFE61AE6,Color.BLUE,0xFFE61AE6};
          sweepGradient0 = new SweepGradient(getWidth()/2, getHeight()/2,colors,null);
          sweepGradient0.setLocalMatrix(matrix);
          innerPaint.setShader(sweepGradient0);
          canvas.drawCircle(getWidth()/2,getHeight()/2,150,innerPaint);
          textPaint.setColor(Color.BLACK);

          outPaint.setColor(0xFF1196EE);
          canvas.drawLine(getWidth()/2-25,getHeight()/2+165,getWidth()/2-25,getHeight(),outPaint);
          canvas.drawLine(getWidth()/2,getHeight()/2+165,getWidth()/2,getHeight(),outPaint);
          canvas.drawLine(getWidth()/2+25,getHeight()/2+165,getWidth()/2+25,getHeight(),outPaint);

          Rect rect = new Rect(getWidth()/2-150,getHeight()/2-150,getWidth()/2+150,getHeight()/2+150);//画一个矩形
          Paint textPaint = new Paint();
          textPaint.setColor(Color.WHITE);
          textPaint.setTextSize(100);
          textPaint.setStyle(Paint.Style.FILL);
        //该方法即为设置基线上那个点究竟是left,center,还是right  这里我设置为center
          textPaint.setTextAlign(Paint.Align.CENTER);

          Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
          float top = fontMetrics.top;//为基线到字体上边框的距离,即上图中的top
          float bottom = fontMetrics.bottom;//为基线到字体下边框的距离,即上图中的bottom
          int baseLineY = (int) (rect.centerY() - top/2 - bottom/2);//基线中间点的y轴计算公式

          canvas.drawText("90%",rect.centerX(),baseLineY,textPaint);
      }

      private void drawCircle(Canvas canvas,int radius){
          float x = getWidth()/2;
          float y = getHeight()/2;
          RectF rectF = new RectF(x-radius,y-radius,x+radius,y+radius);
          canvas.drawArc(rectF,120,300,false,outPaint);
          Path path = new Path();
          path.moveTo(x-radius/2,(float)(y+radius*Math.cos(Math.PI/6)));
          path.quadTo(x-radius/4,(float)(y+radius*Math.cos(Math.PI/6))+20,x-radius/4,(float)(y+radius*Math.cos(Math.PI/6)+100));
          canvas.drawPath(path,outPaint);
           canvas.drawLine(x-radius/4,(float)(y+radius*Math.cos(Math.PI/6)+100),x-radius/4,y*2,outPaint);
          path = new Path();
          path.moveTo(x+radius/2,(float)(y+radius*Math.cos(Math.PI/6)));
          path.quadTo(x+radius/4,(float)(y+radius*Math.cos(Math.PI/6))+20,x+radius/4,(float)(y+radius*Math.cos(Math.PI/6)+100));
         canvas.drawPath(path,outPaint);
         canvas.drawLine(x+radius/4,(float)(y+radius*Math.cos(Math.PI/6)+100),x+radius/4,y*2,outPaint);

      }
      }

最后上效果图,虽然有很大的差距但是细节扣一下还是能看的。


Android 自定义-充电View(一)_第3张图片
ChargeView.png

你可能感兴趣的:(Android 自定义-充电View(一))