Android(安卓)百分比、水波、流量剩余进度球的实现
16lz
2021-01-26
因为项目中有遇到进度的一个需求,目前类似的在实现网络进度加载和流量用量上比较多,所有今天就把代码贴出来,希望有需要的朋友能够有用到。
1.首先是主页面
package com.zhanglu.percentageball;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;/** * * 项目名称:PercentageBall 类名称:MainActivity 类描述: 主页面 创建人:zhanglu 创建时间:2016-6-1 上午9:04:46 修改人:zhanglu 修改时间:2016-6-1 上午9:04:46 修改备注: * * @version * */public class MainActivity extends Activity implements OnClickListener {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findViewById(R.id.button1).setOnClickListener(this);findViewById(R.id.button2).setOnClickListener(this);findViewById(R.id.button3).setOnClickListener(this);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.button1:startActivity(new Intent(this, PercentageBallActivty.class));break;case R.id.button2:startActivity(new Intent(this, PercentageBallListviewActivty.class));break;case R.id.button3:startActivity(new Intent(this, PercentageBallWaveActivty.class));break;default:break;}}}
2.下面是静止页面的代码
package com.zhanglu.percentageball;import com.zhanglu.percentageball.view.PercentageBallView;import android.app.Activity;import android.os.Bundle;/** * * 项目名称:PercentageBall * 类名称:PercentageBallActivty * 类描述: 动态波浪球 * 创建人:zhanglu * 创建时间:2016-6-1 上午9:30:53 * 修改人:zhanglu * 修改时间:2016-6-1 上午9:30:53 * 修改备注: * @version * */public class PercentageBallActivty extends Activity {private PercentageBallView pv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.percentage_ball_activty);pv = (PercentageBallView) findViewById(R.id.ball);pv.setmWaterLevel(0.5f, "10/5");pv.startWave();// 开始执行}}
下面是实现波浪球的效果代码
package com.zhanglu.percentageball.view;import android.annotation.TargetApi;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.Build;import android.os.Handler;import android.os.Parcel;import android.os.Parcelable;import android.util.AttributeSet;import android.view.View;import android.widget.ProgressBar;import com.zhanglu.percentageball.R;/** * * 项目名称:PercentageBall * 类名称:PercentageBallView * 类描述: 实现效果类 * 创建人:zhanglu * 创建时间:2016-6-1 上午11:20:17 * 修改人:zhanglu * 修改时间:2016-6-1 上午11:20:17 * 修改备注: * @version * */@TargetApi(Build.VERSION_CODES.HONEYCOMB)public class PercentageBallView extends View {private Context mContext;private int mScreenWidth;private int mScreenHeight;private Paint mRingPaint;private Paint mCirclePaint;private Paint mWavePaint;private Paint flowPaint;private int mRingSTROKEWidth = 8;private int mCircleSTROKEWidth = 8;private int mLineSTROKEWidth = 1;private Handler mHandler;private long c = 0L;private boolean mStarted = false;private final float f = 0.033F;private int mAlpha = 50;// 透明度private float mAmplitude = 0.0F; // 振幅private float mWaterLevel = 0.0F;// 水高(0~1)private Path mPath;// 绘制文字显示在圆形中间,只是我没有设置,我觉得写在布局上也挺好的private String flowNum = "";// 2/10/** * @param context */public PercentageBallView(Context context) {super(context);// TODO Auto-generated constructor stubmContext = context;init(mContext);}/** * @param context * @param attrs */public PercentageBallView(Context context, AttributeSet attrs) {super(context, attrs);// TODO Auto-generated constructor stubmContext = context;init(mContext);}/** * @param context * @param attrs * @param defStyleAttr */public PercentageBallView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);mContext = context;init(mContext);}public void setmWaterLevel(float mWaterLevel, String str) {this.mWaterLevel = mWaterLevel;this.flowNum = str;}public void setmWaterWave(float mWaterLevel, String str, float mWater) {this.mWaterLevel = mWaterLevel;this.flowNum = str;this.mAmplitude = mWater;}private void init(Context context) {// 外圈mRingPaint = new Paint();mRingPaint.setColor(Color.rgb(75, 210, 243));mRingPaint.setStyle(Paint.Style.STROKE);mRingPaint.setAntiAlias(true);mRingPaint.setStrokeWidth(mRingSTROKEWidth);// 内圈mCirclePaint = new Paint();mCirclePaint.setColor(Color.WHITE);mCirclePaint.setStyle(Paint.Style.STROKE);mCirclePaint.setAntiAlias(true);mCirclePaint.setStrokeWidth(mCircleSTROKEWidth);// 文字flowPaint = new Paint();flowPaint.setColor(Color.BLACK);flowPaint.setStyle(Paint.Style.FILL);flowPaint.setAntiAlias(true);flowPaint.setTextSize(24);// 内填充mWavePaint = new Paint();mWavePaint.setStrokeWidth(1.0F);mWavePaint.setColor(Color.rgb(75, 210, 243));// mWavePaint.setAlpha(mAlpha);mPath = new Path();mHandler = new Handler() {@Overridepublic void handleMessage(android.os.Message msg) {if (msg.what == 0) {invalidate();if (mStarted) {// 不断发消息给自己,使自己不断被重绘mHandler.sendEmptyMessageDelayed(0, 60L);}}}};}@Overrideprotected 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;}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {// TODO Auto-generated method stubsuper.onSizeChanged(w, h, oldw, oldh);mScreenWidth = w;mScreenHeight = h;}@Overrideprotected void onDraw(Canvas canvas) {// TODO Auto-generated method stubsuper.onDraw(canvas);// 得到控件的宽高int width = getWidth();int height = getHeight();setBackgroundColor(Color.WHITE);// 可以自定义色值// 计算当前油量线和水平中线的距离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;}float num = flowPaint.measureText(flowNum);// 如果未开始(未调用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.drawText(flowNum, mScreenWidth * 4 / 8 - num / 2, mScreenHeight * 4 / 8, flowPaint);canvas.restore();}@Overridepublic Parcelable onSaveInstanceState() {Parcelable superState = super.onSaveInstanceState();SavedState ss = new SavedState(superState);ss.progress = (int) c;return ss;}@Overridepublic void onRestoreInstanceState(Parcelable state) {SavedState ss = (SavedState) state;super.onRestoreInstanceState(ss.getSuperState());c = ss.progress;}@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow();// 关闭硬件加速,防止异常unsupported operation exceptionthis.setLayerType(View.LAYER_TYPE_SOFTWARE, null);}@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();}/** * 开始波动 */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();}@Overridepublic void writeToParcel(Parcel out, int flags) {super.writeToParcel(out, flags);out.writeInt(progress);}public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {public SavedState createFromParcel(Parcel in) {return new SavedState(in);}public SavedState[] newArray(int size) {return new SavedState[size];}};}}
运行后效果如下:
好,我们实现了静态的图后,再来实现动态波动的
因为项目需要,是要在listview中实现,所有现在把效果加到listview中,下面是实现代码:
package com.zhanglu.percentageball;import java.util.ArrayList;import android.app.Activity;import android.content.Context;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ListView;import android.widget.TextView;import com.zhanglu.percentageball.view.PercentageBallView;/** * * 项目名称:PercentageBall * 类名称:PercentageBallListviewActivty * 类描述: 实现在listview中波动效果 * 创建人:zhanglu * 创建时间:2016-6-1 上午11:25:15 * 修改人:zhanglu * 修改时间:2016-6-1 上午11:25:15 * 修改备注: * @version * */public class PercentageBallListviewActivty extends Activity {private Context mContext;private ListView listview;private ArrayList mlist = new ArrayList();private MyAdapter mMyAdapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.percentage_ball__listview_activty);mContext = getApplicationContext();listview = (ListView) findViewById(R.id.listView1);mMyAdapter = new MyAdapter(mlist);listview.setAdapter(mMyAdapter);}@Overrideprotected void onResume() {super.onResume();for (int i = 0; i < 30; i++) {pvinfo pv = new pvinfo();pv.setStr((i + 1) + "/" + 30);mlist.add(pv);}mMyAdapter.notifyDataSetChanged();}public class MyAdapter extends BaseAdapter {private ArrayList mlist = null;public MyAdapter(ArrayList mlist2) {this.mlist = mlist2;}public int getCount() {return mlist.size();}public Object getItem(int pos) {return mlist.get(pos);}public long getItemId(int pos) {return pos;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {final ViewHolder viewHolder;if (convertView == null) {convertView = LayoutInflater.from(mContext).inflate(R.layout.percentage_ball__listview_item, null);viewHolder = new ViewHolder();viewHolder.pv = (PercentageBallView) convertView.findViewById(R.id.ball);viewHolder.textView1 = (TextView) convertView.findViewById(R.id.textView1);convertView.setTag(viewHolder);} else {viewHolder = (ViewHolder) convertView.getTag();}viewHolder.textView1.setText("这是第" + (position+1) + " item ");float n = (float) position / 30;viewHolder.pv.setmWaterWave(n, mlist.get(position).getStr(),8f);viewHolder.pv.startWave();return convertView;}public class ViewHolder {public PercentageBallView pv;public TextView textView1;}}public class pvinfo {private float valve;private String str;public float getValve() {return valve;}public void setValve(float valve) {this.valve = valve;}public String getStr() {return str;}public void setStr(String str) {this.str = str;}public pvinfo(float valve, String str) {super();this.valve = valve;this.str = str;}public pvinfo() {super();}}}
来张效果图:
代码下载地址:http://download.csdn.net/detail/meburningg/9537522
更多相关文章
- 让Android设备永不休眠
- Android(安卓)如何关闭Navigation Bar M
- android 启动自动调用自己创建的脚本(应用程序)
- Android(安卓)游戏开发必备的基础知识
- Android(安卓)新建一个lunch项(全志方案)
- Android(安卓)使用RecycleView实现吸附小标题的Demo(附源码)
- android 绘制图片的一部分
- Android(安卓)4.2 设置手机的 Airplane mode
- Android(安卓)Studio 串口jni开发