Android 自定义-充电View(一)

       之前搞完了基础的自定义中的 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
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容