首页 > 系统 > Android > 正文

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

2019-12-12 06:25:54
字体:
来源:转载
供稿:网友

仿水波纹流球进度条控制器,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软件编程有所帮助。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表