一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

Android编程使用自定义View实现水波进度效果示例

时间:2017-02-10 编辑:简简单单 来源:一聚教程网

本文实例讲述了Android编程使用自定义View实现水波进度效果。分享给大家供大家参考,具体如下:

首先上效果图:

简介:

1.自动适应屏幕大小;
2.水波自动横向滚动
3.各种绘制参数可通过修改常量进行控制。

代码不多,注释也比较详细,全部贴上:

(一)自定义组件:

 

 代码如下复制代码

/**

 * 水波进度效果.

 */

publicclassWaterWaveViewextendsView {

  //边框宽度

  privateintSTROKE_WIDTH;

  //组件的宽,高

  privateintwidth, height;

  /**

   * 进度条最大值和当前进度值

   */

  privatefloatmax, progress;

  /**

   * 绘制波浪的画笔

   */

  privatePaint progressPaint;

  //波纹振幅与半径之比。(建议设置:<0.1)

  privatestaticfinalfloatA =0.05f;

  //绘制文字的画笔

  privatePaint textPaint;

  //绘制边框的画笔

  privatePaint circlePaint;

  /**

   * 圆弧圆心位置

   */

  privateintcenterX, centerY;

  //内圆所在的矩形

  privateRectF circleRectF;

  publicWaterWaveView(Context context) {

    super(context);

    init();

  }

  publicWaterWaveView(Context context, AttributeSet attrs) {

    super(context, attrs);

    init();

  }

  publicWaterWaveView(Context context, AttributeSet attrs,intdefStyleAttr) {

    super(context, attrs, defStyleAttr);

    init();

  }

  //初始化

  privatevoidinit() {

    progressPaint =newPaint();

    progressPaint.setColor(Color.parseColor("#77cccc88"));

    progressPaint.setAntiAlias(true);

    textPaint =newPaint();

    textPaint.setColor(Color.WHITE);

    textPaint.setAntiAlias(true);

    circlePaint =newPaint();

    circlePaint.setStyle(Paint.Style.STROKE);

    circlePaint.setAntiAlias(true);

    circlePaint.setColor(Color.parseColor("#33333333"));

    autoRefresh();

  }

  @Override

  protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec) {

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    if(width ==0|| height ==0) {

      width = getWidth();

      height = getHeight();

      //计算圆弧半径和圆心点

      intcircleRadius = Math.min(width, height) >>1;

      STROKE_WIDTH = circleRadius /10;

      circlePaint.setStrokeWidth(STROKE_WIDTH);

      centerX = width /2;

      centerY = height /2;

      VALID_RADIUS = circleRadius - STROKE_WIDTH;

      RADIANS_PER_X = (float) (Math.PI / VALID_RADIUS);

      circleRectF =newRectF(centerX - VALID_RADIUS, centerY - VALID_RADIUS,

          centerX + VALID_RADIUS, centerY + VALID_RADIUS);

    }

  }

  privateRect textBounds =newRect();

  //x方向偏移量

  privateintxOffset;

  @Override

  protectedvoidonDraw(Canvas canvas) {

    super.onDraw(canvas);

    //绘制圆形边框

    canvas.drawCircle(centerX, centerY, VALID_RADIUS + (STROKE_WIDTH >>1), circlePaint);

    //绘制水波曲线

    canvas.drawPath(getWavePath(xOffset), progressPaint);

    //绘制文字

    textPaint.setTextSize(VALID_RADIUS >>1);

    String text1 = String.valueOf(progress);

    //测量文字长度

    floatw1 = textPaint.measureText(text1);

    //测量文字高度

    textPaint.getTextBounds("8",0,1, textBounds);

    floath1 = textBounds.height();

    floatextraW = textPaint.measureText("8") /3;

    canvas.drawText(text1, centerX - w1 /2- extraW, centerY + h1 /2, textPaint);

    textPaint.setTextSize(VALID_RADIUS /6);

    textPaint.getTextBounds("M",0,1, textBounds);

    floath2 = textBounds.height();

    canvas.drawText("M", centerX + w1 /2- extraW +5, centerY - (h1 /2- h2), textPaint);

    String text3 ="共"+ String.valueOf(max) +"M";

    floatw3 = textPaint.measureText(text3,0, text3.length());

    textPaint.getTextBounds("M",0,1, textBounds);

    floath3 = textBounds.height();

    canvas.drawText(text3, centerX - w3 /2, centerY + (VALID_RADIUS >>1) + h3 /2, textPaint);

    String text4 ="流量剩余";

    floatw4 = textPaint.measureText(text4,0, text4.length());

    textPaint.getTextBounds(text4,0, text4.length(), textBounds);

    floath4 = textBounds.height();

    canvas.drawText(text4, centerX - w4 /2, centerY - (VALID_RADIUS >>1) + h4 /2, textPaint);

  }

  //绘制水波的路径

  privatePath wavePath;

  //每一个像素对应的弧度数

  privatefloatRADIANS_PER_X;

  //去除边框后的半径(即内圆半径)

  privateintVALID_RADIUS;

  /**

   * 获取水波曲线(包含圆弧部分)的Path.

   *

   * @param xOffset x方向像素偏移量.

   */

  privatePath getWavePath(intxOffset) {

    if(wavePath ==null) {

      wavePath =newPath();

    }else{

      wavePath.reset();

    }

    float[] startPoint =newfloat[2];//波浪线起点

    float[] endPoint =newfloat[2];//波浪线终点

    for(inti =0; i <= VALID_RADIUS *2; i +=2) {

      floatx = centerX - VALID_RADIUS + i;

      floaty = (float) (centerY + VALID_RADIUS * (1.0f + A) *2* (0.5f - progress / max)

          + VALID_RADIUS * A * Math.sin((xOffset + i) * RADIANS_PER_X));

      //只计算内圆内部的点,边框上的忽略

      if(calDistance(x, y, centerX, centerY) > VALID_RADIUS) {

        if(x < centerX) {

          continue;//左边框,继续循环

        }else{

          break;//右边框,结束循环

        }

      }

      //第1个点

      if(wavePath.isEmpty()) {

        startPoint[0] = x;

        startPoint[1] = y;

        wavePath.moveTo(x, y);

      }else{

        wavePath.lineTo(x, y);

      }

      endPoint[0] = x;

      endPoint[1] = y;

    }

    if(wavePath.isEmpty()) {

      if(progress / max >=0.5f) {

        //满格

        wavePath.moveTo(centerX, centerY - VALID_RADIUS);

        wavePath.addCircle(centerX, centerY, VALID_RADIUS, Path.Direction.CW);

      }else{

        //空格

        returnwavePath;

      }

    }else{

      //添加圆弧部分

      floatstartDegree = calDegreeByPosition(startPoint[0], startPoint[1]);//0~180

      floatendDegree = calDegreeByPosition(endPoint[0], endPoint[1]);//180~360

      wavePath.arcTo(circleRectF, endDegree -360, startDegree - (endDegree -360));

    }

    returnwavePath;

  }

  privatefloatcalDistance(floatx1,floaty1,floatx2,floaty2) {

    return(float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));

  }

  //根据当前位置,计算出进度条已经转过的角度。

  privatefloatcalDegreeByPosition(floatcurrentX,floatcurrentY) {

    floata1 = (float) (Math.atan(1.0f * (centerX - currentX) / (currentY - centerY)) / Math.PI *180);

    if(currentY < centerY) {

      a1 +=180;

    }elseif(currentY > centerY && currentX > centerX) {

      a1 +=360;

    }

    returna1 +90;

  }

  publicvoidsetMax(intmax) {

    this.max = max;

    invalidate();

  }

  //直接设置进度值(同步)

  publicvoidsetProgressSync(floatprogress) {

    this.progress = progress;

    invalidate();

  }

  /**

   * 自动刷新页面,创造水波效果。组件销毁后该线城将自动停止。

   */

  privatevoidautoRefresh() {

    newThread(newRunnable() {

      @Override

      publicvoidrun() {

        while(!detached) {

          xOffset += (VALID_RADIUS >>4);

          SystemClock.sleep(100);

          postInvalidate();

        }

      }

    }).start();

  }

  //标记View是否已经销毁

  privatebooleandetached =false;

  @Override

  protectedvoidonDetachedFromWindow() {

    super.onDetachedFromWindow();

    detached =true;

  }

}

 

(二)使用方法:

在xml布局中引入上述组件,然后在activity或fragment中设置属性:

 

 代码如下复制代码

WaterWaveView bar = (WaterWaveView) getActivity().findViewById(R.id.water_wave_view);

    bar.setMax(500);

    bar.setProgressSync(361.8f);

 

热门栏目