Android仿水波纹流量球进度条控制器

仿水波纹流球进度条控制器,Android实现高端大气的主流特效,供大家参考,具体内容如下

效果图:

CircleView

这里主要是实现中心圆以及水波特效

package com.lgl.circleview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ProgressBar;

/**
 * 水波圆
 *
 * @author lgl
 *
 */
public class CircleView extends View {

 private Context mContext;

 private int mScreenWidth;
 private int mScreenHeight;

 private Paint mRingPaint;
 private Paint mCirclePaint;
 private Paint mWavePaint;
 private Paint linePaint;
 private Paint flowPaint;
 private Paint leftPaint;

 private int mRingSTROKEWidth = 15;
 private int mCircleSTROKEWidth = 2;
 private int mLineSTROKEWidth = 1;

 private int mCircleColor = Color.WHITE;
 private int mRingColor = Color.WHITE;
 private int mWaveColor = Color.WHITE;

 private Handler mHandler;
 private long c = 0L;
 private boolean mStarted = false;
 private final float f = 0.033F;
 private int mAlpha = 50;// 透明度
 private float mAmplitude = 10.0F; // 振幅
 private float mWaterLevel = 0.5F;// 水高(0~1)
 private Path mPath;

 // 绘制文字显示在圆形中间,只是我没有设置,我觉得写在布局上也挺好的
 private String flowNum = "";
 private String flowLeft = "还剩余";

 /**
  * @param context
  */
 public CircleView(Context context) {
  super(context);
  // TODO Auto-generated constructor stub
  mContext = context;
  init(mContext);
 }

 /**
  * @param context
  * @param attrs
  */
 public CircleView(Context context, AttributeSet attrs) {
  super(context, attrs);
  // TODO Auto-generated constructor stub
  mContext = context;
  init(mContext);
 }

 /**
  * @param context
  * @param attrs
  * @param defStyleAttr
  */
 public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  // TODO Auto-generated constructor stub
  mContext = context;
  init(mContext);
 }

 public void setmWaterLevel(float mWaterLevel) {
  this.mWaterLevel = mWaterLevel;
 }

 private void init(Context context) {
  mRingPaint = new Paint();
  mRingPaint.setColor(mRingColor);
  mRingPaint.setAlpha(50);
  mRingPaint.setStyle(Paint.Style.STROKE);
  mRingPaint.setAntiAlias(true);
  mRingPaint.setStrokeWidth(mRingSTROKEWidth);

  mCirclePaint = new Paint();
  mCirclePaint.setColor(mCircleColor);
  mCirclePaint.setStyle(Paint.Style.STROKE);
  mCirclePaint.setAntiAlias(true);
  mCirclePaint.setStrokeWidth(mCircleSTROKEWidth);

  linePaint = new Paint();
  linePaint.setColor(mCircleColor);
  linePaint.setStyle(Paint.Style.STROKE);
  linePaint.setAntiAlias(true);
  linePaint.setStrokeWidth(mLineSTROKEWidth);

  flowPaint = new Paint();
  flowPaint.setColor(mCircleColor);
  flowPaint.setStyle(Paint.Style.FILL);
  flowPaint.setAntiAlias(true);
  flowPaint.setTextSize(36);

  leftPaint = new Paint();
  leftPaint.setColor(mCircleColor);
  leftPaint.setStyle(Paint.Style.FILL);
  leftPaint.setAntiAlias(true);
  leftPaint.setTextSize(36);

  mWavePaint = new Paint();
  mWavePaint.setStrokeWidth(1.0F);
  mWavePaint.setColor(mWaveColor);
  mWavePaint.setAlpha(mAlpha);
  mPath = new Path();

  mHandler = new Handler() {
   @Override
   public void handleMessage(android.os.Message msg) {
    if (msg.what == 0) {
     invalidate();
     if (mStarted) {
      // 不断发消息给自己,使自己不断被重绘
      mHandler.sendEmptyMessageDelayed(0, 60L);
     }
    }
   }
  };
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  int width = measure(widthMeasureSpec, true);
  int height = measure(heightMeasureSpec, false);
  if (width < height) {
   setMeasuredDimension(width, width);
  } else {
   setMeasuredDimension(height, height);
  }

 }

 /**
  * @category 测量
  * @param measureSpec
  * @param isWidth
  * @return
  */
 private int measure(int measureSpec, boolean isWidth) {
  int result;
  int mode = MeasureSpec.getMode(measureSpec);
  int size = MeasureSpec.getSize(measureSpec);
  int padding = isWidth ? getPaddingLeft() + getPaddingRight()
    : getPaddingTop() + getPaddingBottom();
  if (mode == MeasureSpec.EXACTLY) {
   result = size;
  } else {
   result = isWidth ? getSuggestedMinimumWidth()
     : getSuggestedMinimumHeight();
   result += padding;
   if (mode == MeasureSpec.AT_MOST) {
    if (isWidth) {
     result = Math.max(result, size);
    } else {
     result = Math.min(result, size);
    }
   }
  }
  return result;
 }

 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  // TODO Auto-generated method stub
  super.onSizeChanged(w, h, oldw, oldh);
  mScreenWidth = w;
  mScreenHeight = h;
 }

 @Override
 protected void onDraw(Canvas canvas) {
  // TODO Auto-generated method stub
  super.onDraw(canvas);
  // 得到控件的宽高
  int width = getWidth();
  int height = getHeight();
  setBackgroundColor(mContext.getResources().getColor(R.color.main_bg));
  // 计算当前油量线和水平中线的距离
  float centerOffset = Math.abs(mScreenWidth / 2 * mWaterLevel
    - mScreenWidth / 4);
  // 计算油量线和与水平中线的角度
  float horiAngle = (float) (Math.asin(centerOffset / (mScreenWidth / 4)) * 180 / Math.PI);
  // 扇形的起始角度和扫过角度
  float startAngle, sweepAngle;
  if (mWaterLevel > 0.5F) {
   startAngle = 360F - horiAngle;
   sweepAngle = 180F + 2 * horiAngle;
  } else {
   startAngle = horiAngle;
   sweepAngle = 180F - 2 * horiAngle;
  }

  canvas.drawLine(mScreenWidth * 3 / 8, mScreenHeight * 5 / 8,
    mScreenWidth * 5 / 8, mScreenHeight * 5 / 8, linePaint);

  float num = flowPaint.measureText(flowNum);
  canvas.drawText(flowNum, mScreenWidth * 4 / 8 - num / 2,
    mScreenHeight * 4 / 8, flowPaint);
  float left = leftPaint.measureText(flowLeft);
  canvas.drawText(flowLeft, mScreenWidth * 4 / 8 - left / 2,
    mScreenHeight * 3 / 8, leftPaint);

  // 如果未开始(未调用startWave方法),绘制一个扇形
  if ((!mStarted) || (mScreenWidth == 0) || (mScreenHeight == 0)) {
   // 绘制,即水面静止时的高度
   RectF oval = new RectF(mScreenWidth / 4, mScreenHeight / 4,
     mScreenWidth * 3 / 4, mScreenHeight * 3 / 4);
   canvas.drawArc(oval, startAngle, sweepAngle, false, mWavePaint);
   return;
  }
  // 绘制,即水面静止时的高度
  // 绘制,即水面静止时的高度
  RectF oval = new RectF(mScreenWidth / 4, mScreenHeight / 4,
    mScreenWidth * 3 / 4, mScreenHeight * 3 / 4);
  canvas.drawArc(oval, startAngle, sweepAngle, false, mWavePaint);

  if (this.c >= 8388607L) {
   this.c = 0L;
  }
  // 每次onDraw时c都会自增
  c = (1L + c);
  float f1 = mScreenHeight * (1.0F - (0.25F + mWaterLevel / 2))
    - mAmplitude;
  // 当前油量线的长度
  float waveWidth = (float) Math.sqrt(mScreenWidth * mScreenWidth / 16
    - centerOffset * centerOffset);
  // 与圆半径的偏移量
  float offsetWidth = mScreenWidth / 4 - waveWidth;

  int top = (int) (f1 + mAmplitude);
  mPath.reset();
  // 起始振动X坐标,结束振动X坐标
  int startX, endX;
  if (mWaterLevel > 0.50F) {
   startX = (int) (mScreenWidth / 4 + offsetWidth);
   endX = (int) (mScreenWidth / 2 + mScreenWidth / 4 - offsetWidth);
  } else {
   startX = (int) (mScreenWidth / 4 + offsetWidth - mAmplitude);
   endX = (int) (mScreenWidth / 2 + mScreenWidth / 4 - offsetWidth + mAmplitude);
  }
  // 波浪效果
  while (startX < endX) {
   int startY = (int) (f1 - mAmplitude
     * Math.sin(Math.PI
       * (2.0F * (startX + this.c * width * this.f))
       / width));
   canvas.drawLine(startX, startY, startX, top, mWavePaint);
   startX++;
  }
  canvas.drawCircle(mScreenWidth / 2, mScreenHeight / 2, mScreenWidth / 4
    + mRingSTROKEWidth / 2, mRingPaint);

  canvas.drawCircle(mScreenWidth / 2, mScreenHeight / 2,
    mScreenWidth / 4, mCirclePaint);
  canvas.restore();
 }

 @Override
 public Parcelable onSaveInstanceState() {
  Parcelable superState = super.onSaveInstanceState();
  SavedState ss = new SavedState(superState);
  ss.progress = (int) c;
  return ss;
 }

 @Override
 public void onRestoreInstanceState(Parcelable state) {
  SavedState ss = (SavedState) state;
  super.onRestoreInstanceState(ss.getSuperState());
  c = ss.progress;
 }

 @Override
 protected void onAttachedToWindow() {
  super.onAttachedToWindow();
  // 关闭硬件加速,防止异常unsupported operation exception
  this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
 }

 @Override
 protected void onDetachedFromWindow() {
  super.onDetachedFromWindow();
 }

 /**
  * @category 开始波动
  */
 public void startWave() {
  if (!mStarted) {
   this.c = 0L;
   mStarted = true;
   this.mHandler.sendEmptyMessage(0);
  }
 }

 /**
  * @category 停止波动
  */
 public void stopWave() {
  if (mStarted) {
   this.c = 0L;
   mStarted = false;
   this.mHandler.removeMessages(0);
  }
 }

 /**
  * @category 保存状态
  */
 static class SavedState extends BaseSavedState {
  int progress;

  /**
   * Constructor called from {@link ProgressBar#onSaveInstanceState()}
   */
  SavedState(Parcelable superState) {
   super(superState);
  }

  /**
   * Constructor called from {@link #CREATOR}
   */
  private SavedState(Parcel in) {
   super(in);
   progress = in.readInt();
  }

  @Override
  public void writeToParcel(Parcel out, int flags) {
   super.writeToParcel(out, flags);
   out.writeInt(progress);
  }

  public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
   public SavedState createFromParcel(Parcel in) {
    return new SavedState(in);
   }

   public SavedState[] newArray(int size) {
    return new SavedState[size];
   }
  };
 }

}

我们运行一下

其实他是十分的空旷的,所以也值得我们去定制,我们在中间加个流量显示,再加个进度条
activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="@color/main_bg" >

 <TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_alignParentTop="true"
  android:layout_centerHorizontal="true"
  android:layout_marginTop="10dp"
  android:text="流量"
  android:textColor="@android:color/white"
  android:textSize="18sp" />

 <com.lgl.circleview.CircleView
  android:id="@+id/wave_view"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:layout_centerInParent="true" />

 <TextView
  android:id="@+id/power"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_centerInParent="true"
  android:textColor="@android:color/white" />

 <SeekBar
  android:id="@+id/seekBar"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_alignParentBottom="true"
  android:layout_marginBottom="150dp" />

</RelativeLayout>

我们要实现这个,就要调用它的初始化以及start方法

 mCircleView = (CircleView) findViewById(R.id.wave_view);
  // 设置多高,float,0.1-1F
  mCircleView.setmWaterLevel(0.1F);
  // 开始执行
  mCircleView.startWave();

别忘了activity销毁的时候把它回收哦
@Override
 protected void onDestroy() {
  // TODO Auto-generated method stub
  mCircleView.stopWave();
  mCircleView = null;
  super.onDestroy();
 }

我们再运行一遍

但是我们要怎么让水波纹随着进度条一起上升下降尼?,这里我们就要用到我们刚才写的SeekBar了,我们实现它的

setOnSeekBarChangeListener来监听,这样我们就要复写他的三个方法,这里我们只要用到一个
public void onProgressChanged(SeekBar seekBar, int progress,
     boolean fromUser) {
    //跟随进度条滚动
    mCircleView.setmWaterLevel((float) progress / 100);
    }

这里,我们要这样算的,我们设置高度的单位是float,也就是从0-1F,而我们的进度是int progress,从0-100,我们就要用(float) progress / 100)并且强转来得到单位,好了,我们现在水波纹的高度就是随着我们的进度条一起变化了,我们再来运行一下

好的,这样的话,我们就只剩下一个了,就是让大小随着我们的进度条变化了,这里我们因为更新UI不能再主线程中操作,所以我们需要用到我们的老伙计Handler了,但是用到handler还不够,我们的进度条数值也是在内部类里面,所以这里我们需要用到Handler来传值了,这里我们用的是Bundle,我们还是在onProgressChanged方法中操作了

 //创建一个消息
    Message message = new Message();
    Bundle bundle = new Bundle();
    //put一个int值
    bundle.putInt("progress", progress);
    //装载
    message.setData(bundle);
    //发送消息
    handler.sendMessage(message);
    //创建表示
    message.what = 1;

消息发送过去了,我们就在前面写个Handler去接收就是了

 private Handler handler = new Handler() {
  public void handleMessage(android.os.Message msg) {
   if (msg.what == 1) {
    int num = msg.getData().getInt("progress");
    Log.i("num", num + "");
    power.setText((float) num / 100 * max + "M/" + max + "M");
   }
  }
 };

这里的计算公式尼,是当前的数值/100得到百分比再去*最大值。我们现在可以完整的运行一下了,其实和最上面运行的图片是一样的

MainActivity

package com.lgl.circleview;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.SeekBar;
import android.widget.TextView;

public class MainActivity extends Activity {

 private CircleView mCircleView;
 private SeekBar mSeekBar;
 private TextView power;
 private int max = 1024;
 private int min = 102;

 private Handler handler = new Handler() {
 public void handleMessage(android.os.Message msg) {
  if (msg.what == 1) {
  int num = msg.getData().getInt("progress");
  Log.i("num", num + "");
  power.setText((float) num / 100 * max + "M/" + max + "M");
  }
 }
 };

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 getActionBar().hide();
 setContentView(R.layout.activity_main);

 power = (TextView) findViewById(R.id.power);
 power.setText(min + "M/" + max + "M");

 mCircleView = (CircleView) findViewById(R.id.wave_view);
 // 设置多高,float,0.1-1F
 mCircleView.setmWaterLevel(0.1F);
 // 开始执行
 mCircleView.startWave();

 mSeekBar = (SeekBar) findViewById(R.id.seekBar);
 mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
  @Override
  public void onProgressChanged(SeekBar seekBar, int progress,
   boolean fromUser) {
  mCircleView.setmWaterLevel((float) progress / 100);
  // 创建一个消息
  Message message = new Message();
  Bundle bundle = new Bundle();
  // put一个int值
  bundle.putInt("progress", progress);
  // 装载
  message.setData(bundle);
  // 发送消息
  handler.sendMessage(message);
  // 创建表示
  message.what = 1;
  }

  @Override
  public void onStartTrackingTouch(SeekBar seekBar) {

  }

  @Override
  public void onStopTrackingTouch(SeekBar seekBar) {

  }
 });
 }

 @Override
 protected void onDestroy() {
 // TODO Auto-generated method stub
 mCircleView.stopWave();
 mCircleView = null;
 super.onDestroy();
 }
}

代码下载:Android仿水波纹流量球进度条

以上就是本文的全部内容,希望对大家学习Android软件编程有所帮助。

(0)

相关推荐

  • Android项目实战手把手教你画圆形水波纹loadingview

    本文实例讲解的是如何画一个满满圆形水波纹loadingview,这类效果应用场景很多,比如内存占用百分比之类的,分享给大家供大家参考,具体内容如下 效果图如下: 预备的知识: 1.贝塞尔曲线    如果你不了解,可以来这里进行基础知识储备:神奇的贝塞尔曲线 2.Paint.setXfermode()  以及PorterDuffXfermode 千万不要被这个b的名字吓到,不熟悉看到可能会认为很难记,其实 只要站在巨人的丁丁上 还是很简单的. 好了 废话不多说 ,跟我一步步来做一个炫酷的view吧

  • Android自定义view实现水波纹进度球效果

    今天我们要实现的这个view没有太多交互性的view,所以就继承view. 自定义view的套路,套路很深 1.获取我们自定义属性attrs(可省略) 2.重写onMeasure方法,计算控件的宽和高 3.重写onDraw方法,绘制我们的控件 这么看来,自定义view的套路很清晰嘛. 我们看下今天的效果图,其中一个是放慢的效果(时间调的长) 我们按照套路来. 一.自定义属性 <declare-styleable name="WaveProgressView"> <at

  • Android实现点击Button产生水波纹效果

    先上图,看看接下来我要向大家介绍的是个什么东西,如下图: 接下来要介绍的就是如何实现上述图中的波纹效果,这种效果如果大家没有体验过的话,可以看看百度手机卫士或者360手机卫士,里面的按钮点击效果都是这样的,另外Android 5.0以上的版本也出现了这种效果.不多说,下面聊聊具体的怎么实现. 首先大家看到的是三个button,水波纹的出现给我们的错觉是直接将波纹绘制在button上面的,但是这样能做到吗?首先button自己有background和src,如果把半透明的水波纹当作backgrou

  • Android实现水波纹效果

    一.效果 点击开始: 点击停止: 二.在MainActivity中 import android.graphics.Paint; import android.os.Bundle; import android.support.v4.view.animation.LinearOutSlowInInterpolator; import android.support.v7.app.AppCompatActivity; import android.view.View; import android

  • Android 自定义view实现水波纹动画效果

    在实际的开发中,很多时候还会遇到相对比较复杂的需求,比如产品妹纸或UI妹纸在哪看了个让人兴奋的效果,兴致高昂的来找你,看了之后目的很明确,当然就是希望你能给她: 在这样的关键时候,身子板就一定得硬了,可千万别说不行,爷们儿怎么能说不行呢: 好了,为了让大家都能给妹纸们想要的,后面会逐渐分享一些比较比较不错的效果,目的只有一个,通过自定义view实现我们所能实现的动效: 今天主要分享水波纹效果: 1.标准正余弦水波纹: 2.非标准圆形液柱水波纹: 虽说都是水波纹,但两者在实现上差异是比较大的,一个

  • Android自定义WaveProgressView实现水波纹加载需求

    先看效果图: 你可以定义成你项目的logo图片,可以设置水波颜色.波长.波宽.字体大小.颜色.进度条的最大值,当前进度值,还可以设置波纹震动的快慢.当设置一个进度不变的时候,打开时还有一个动画填满的效果(比如第二个流量显示,这里图片没有截出这个效果). 源码地址 1. 如何使用 1.1 在布局文件中 添加自定义控件: <cn.fanrunqi.waveprogressview.WaveProgressView android:id="@+id/waveProgressbar" a

  • Android实现兼容的水波纹效果

    先看看效果图 其实,要实现这一效果很简单,只要分drawable和drawablev21两个文件夹就好了. 普通情况下的selector: <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@c

  • Android特效之水波纹的实现

    前言 水波纹特效,想必大家或多或少见过,在我的印象中,大致有如下几种: 支付宝 "咻咻咻" 式 流量球 "荡漾" 式 真实的水波纹效果,基于Bitmap处理式 话不多说,先来看看效果: 填充式水波纹,间距相等 非填充式水波纹,间距相等 非填充式水波纹,间距不断变大 填充式水波纹,间距不断变小 想必大家已经知道基本的原理了,就是用Canvas来画嘛,但可不是简单的画哦,请往下看. 分析 这种类型的水波纹,其实无非就是画圆而已,在给定的矩形中,一个个圆由最小半径扩大到最

  • Android实现自定义华丽的水波纹效果

    先来看看效果 实现效果 模拟水波纹的效果:点击屏幕就有圆环出现,半径从小到大,透明度从大到小(0为透明) 实现思路 1.自定义类继承View. 2.定义每个圆环的实体类 Wave,并初始化绘制圆环的画笔的数据. 3.重写onTouchEvent方法,down时,获得坐标点,做为圆环圆心. 4.发送handler信息,对数据进行修改,刷新页面. 5.重写onDraw方法,绘制一个圆环. 1. 自定义类继承View 新建WaterWaveView2类继承View public class Water

  • Android自定义View 实现水波纹动画引导效果

    一.实现效果图 二.实现代码 1.自定义view package com.czhappy.showintroduce.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Pat

随机推荐