软件编程
位置:首页>> 软件编程>> Android编程>> Android仿水波纹流量球进度条控制器

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

作者:刘某人程序员  发布时间:2022-09-02 01:13:03 

标签:Android,水波纹,流量球,进度条

仿水波纹流球进度条控制器,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];
  }
 };
}

}

我们运行一下

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

其实他是十分的空旷的,所以也值得我们去定制,我们在中间加个流量显示,再加个进度条
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();
}

我们再运行一遍

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

但是我们要怎么让水波纹随着进度条一起上升下降尼?,这里我们就要用到我们刚才写的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)并且强转来得到单位,好了,我们现在水波纹的高度就是随着我们的进度条一起变化了,我们再来运行一下

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

好的,这样的话,我们就只剩下一个了,就是让大小随着我们的进度条变化了,这里我们因为更新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得到百分比再去*最大值。我们现在可以完整的运行一下了,其实和最上面运行的图片是一样的

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

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仿水波纹流量球进度条

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com