美文网首页
Android 自定义-充电View(一)

Android 自定义-充电View(一)

作者: 就爱烫卷发 | 来源:发表于2019-06-19 00:56 被阅读0次

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

    充电.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);
      
    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);
    
          }
          }
    

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


    ChargeView.png

    相关文章

      网友评论

          本文标题:Android 自定义-充电View(一)

          本文链接:https://www.haomeiwen.com/subject/ifycqctx.html