Android分享一个流量显示界面
http://blog.csdn.net/wangjinyu501/article/details/39527021
版本:1.0
日期:2014.8.9 2014.9.24
版权:© 2014 kince 转载注明出处
波形效果有几种不同的呈现形式,比如从中间向四周散开的波形,也就是熟知的水涟漪;还有上下波动的曲线,像五线谱等。英文中可以称作Wave或者Ripple,所以暂且叫它们WaveView、WaveLayout、RippleView、RippleLayout,接下来开始实现这些效果。
首先看一下Solo 火爆足球动态壁纸,
下面中间的按钮就是一个波形按钮,它会不断地向四周辐射,由于是静态图,如果想体验真实效果可以另行下载。这种效果的实现思路是不断绘制圆形,当然半径也要不断变化,透明度也是一样。代码如下:
-
/**
-
*
-
*/
-
package com.kince.rippleview;
-
-
import android.content.Context;
-
import android.graphics.Bitmap;
-
import android.graphics.BitmapFactory;
-
import android.graphics.Canvas;
-
import android.graphics.Color;
-
import android.graphics.Paint;
-
import android.graphics.RectF;
-
import android.os.Handler;
-
import android.os.Message;
-
import android.util.AttributeSet;
-
import android.view.View;
-
-
/**
-
* @author kince
-
* @category 波纹
-
* @since 2014.8.9
-
* @version v1.0.0
-
*
-
*/
-
public class RippleView extends View {
-
-
private int mScreenWidth;
-
private int mScreenHeight;
-
-
private Bitmap mRippleBitmap;
-
private Paint mRipplePaint = new Paint();
-
-
private int mBitmapWidth;
-
private int mBitmapHeight;
-
-
private boolean isStartRipple;
-
-
private int heightPaddingTop;
-
private int heightPaddingBottom;
-
private int widthPaddingLeft;
-
private int widthPaddingRight;
-
-
private RectF mRect = new RectF();
-
-
private int rippleFirstRadius = 0;
-
private int rippleSecendRadius = -33;
-
private int rippleThirdRadius = -66;
-
-
private Paint textPaint = new Paint();
-
private String mText="点击我吧";
-
-
private Handler handler = new Handler() {
-
@Override
-
public void handleMessage(Message msg) {
-
// TODO Auto-generated method stub
-
super.handleMessage(msg);
-
invalidate();
-
if (isStartRipple) {
-
rippleFirstRadius++;
-
if (rippleFirstRadius > 100) {
-
rippleFirstRadius = 0;
-
}
-
rippleSecendRadius++;
-
if (rippleSecendRadius > 100) {
-
rippleSecendRadius = 0;
-
}
-
rippleThirdRadius++;
-
if (rippleThirdRadius > 100) {
-
rippleThirdRadius = 0;
-
}
-
sendEmptyMessageDelayed(0, 20);
-
}
-
}
-
};
-
-
/**
-
* @param context
-
*/
-
public RippleView(Context context) {
-
super(context);
-
// TODO Auto-generated constructor stub
-
init();
-
}
-
-
/**
-
* @param context
-
* @param attrs
-
*/
-
public RippleView(Context context, AttributeSet attrs) {
-
super(context, attrs);
-
// TODO Auto-generated constructor stub
-
init();
-
}
-
-
/**
-
* @param context
-
* @param attrs
-
* @param defStyleAttr
-
*/
-
public RippleView(Context context, AttributeSet attrs, int defStyleAttr) {
-
super(context, attrs, defStyleAttr);
-
// TODO Auto-generated constructor stub
-
init();
-
}
-
-
private void init() {
-
mRipplePaint.setColor(4961729);
-
mRipplePaint.setAntiAlias(true);
-
mRipplePaint.setStyle(Paint.Style.FILL);
-
-
textPaint.setTextSize(26);
-
textPaint.setAntiAlias(true);
-
textPaint.setStyle(Paint.Style.FILL);
-
textPaint.setColor(Color.WHITE);
-
-
mRippleBitmap = BitmapFactory.decodeStream(getResources()
-
.openRawResource(R.drawable.easy3d_ic_apply));
-
mBitmapWidth = mRippleBitmap.getWidth();
-
mBitmapHeight = mRippleBitmap.getHeight();
-
}
-
-
@Override
-
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-
// TODO Auto-generated method stub
-
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
int mh = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
-
int mw = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
-
if (mBitmapWidth < 2 * mBitmapHeight) {
-
mBitmapWidth = (2 * mBitmapHeight);
-
}
-
setMeasuredDimension(mBitmapWidth, mBitmapHeight);
-
}
-
-
@Override
-
protected void onDraw(Canvas canvas) {
-
// TODO Auto-generated method stub
-
super.onDraw(canvas);
-
if (isStartRipple) {
-
float f1 = 3 * mBitmapHeight / 10;
-
mRipplePaint.setAlpha(255);
-
canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight,
-
7 * mBitmapHeight / 10, mRipplePaint);
-
int i1 = (int) (220.0F - (220.0F - 0.0F) / 100.0F
-
* rippleFirstRadius);
-
mRipplePaint.setAlpha(i1);
-
canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight, 7
-
* mBitmapHeight / 10 + f1 * rippleFirstRadius / 100.0F,
-
mRipplePaint);
-
if (rippleSecendRadius >= 0) {
-
int i3 = (int) (220.0F - (220.0F - 0.0F) / 100.0F
-
* rippleSecendRadius);
-
mRipplePaint.setAlpha(i3);
-
canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight,
-
7 * mBitmapHeight / 10 + f1 * rippleSecendRadius
-
/ 100.0F, mRipplePaint);
-
}
-
if (rippleThirdRadius >= 0) {
-
int i2 = (int) (220.0F - (220.0F - 0.0F) / 100.0F
-
* rippleThirdRadius);
-
mRipplePaint.setAlpha(i2);
-
canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight, 7
-
* mBitmapHeight / 10 + f1 * rippleThirdRadius / 100.0F,
-
mRipplePaint);
-
}
-
-
}
-
mRipplePaint.setAlpha(30);
-
canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight, mBitmapHeight,
-
mRipplePaint);
-
mRipplePaint.setAlpha(120);
-
canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight,
-
9 * mBitmapHeight / 10, mRipplePaint);
-
mRipplePaint.setAlpha(180);
-
canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight,
-
8 * mBitmapHeight / 10, mRipplePaint);
-
mRipplePaint.setAlpha(255);
-
canvas.drawCircle(mBitmapWidth / 2, mBitmapHeight,
-
7 * mBitmapHeight / 10, mRipplePaint);
-
float length = textPaint.measureText(mText);
-
canvas.drawText(mText, (mBitmapWidth - length) / 2,
-
mBitmapHeight * 3 / 4, textPaint);
-
-
}
-
-
@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;
-
confirmSize();
-
invalidate();
-
-
}
-
-
private void confirmSize() {
-
int minScreenSize = Math.min(mScreenWidth, mScreenHeight);
-
int widthOverSize = mScreenWidth - minScreenSize;
-
int heightOverSize = mScreenHeight - minScreenSize;
-
heightPaddingTop = (getPaddingTop() + heightOverSize / 2);
-
heightPaddingBottom = (getPaddingBottom() + heightOverSize / 2);
-
widthPaddingLeft = (getPaddingLeft() + widthOverSize / 2);
-
widthPaddingRight = (getPaddingRight() + widthOverSize / 2);
-
-
int width = getWidth();
-
int height = getHeight();
-
-
mRect = new RectF(widthPaddingLeft, heightPaddingTop, width
-
- widthPaddingRight, height * 2 - heightPaddingBottom);
-
-
}
-
-
public void stratRipple() {
-
isStartRipple = true;
-
handler.sendEmptyMessage(0);
-
}
-
-
}
下图是某个应用的流量显示界面,使用的是上面说的第二种形式。
实现上面效果的思路是使用正弦或者余弦曲线,代码如下:
-
/**
-
*
-
*/
-
package com.kince.waveview;
-
-
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 kince
-
* @category View必须是正方形
-
*
-
*/
-
public class WaterWaveView 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 mWateLevel = 0.5F;// 水高(0~1)
-
private Path mPath;
-
-
private String flowNum = "1024M";
-
private String flowLeft = "还剩余";
-
-
/**
-
* @param context
-
*/
-
public WaterWaveView(Context context) {
-
super(context);
-
// TODO Auto-generated constructor stub
-
mContext = context;
-
init(mContext);
-
}
-
-
/**
-
* @param context
-
* @param attrs
-
*/
-
public WaterWaveView(Context context, AttributeSet attrs) {
-
super(context, attrs);
-
// TODO Auto-generated constructor stub
-
mContext = context;
-
init(mContext);
-
}
-
-
/**
-
* @param context
-
* @param attrs
-
* @param defStyleAttr
-
*/
-
public WaterWaveView(Context context, AttributeSet attrs, int defStyleAttr) {
-
super(context, attrs, defStyleAttr);
-
// TODO Auto-generated constructor stub
-
mContext = context;
-
init(mContext);
-
}
-
-
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(18);
-
-
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.holo_purple2));
-
-
canvas.drawCircle(mScreenWidth / 2, mScreenHeight / 2,
-
mScreenWidth / 4, mRingPaint);
-
-
canvas.drawCircle(mScreenWidth / 2, mScreenHeight / 2, mScreenWidth / 4
-
- mRingSTROKEWidth / 2, mCirclePaint);
-
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 + mRingSTROKEWidth / 2,
-
mScreenHeight / 4 + mRingSTROKEWidth / 2, mScreenWidth * 3
-
/ 4 - mRingSTROKEWidth / 2, mScreenHeight * 3 / 4
-
- mRingSTROKEWidth / 2);// 设置个新的长方形,扫描测量
-
canvas.drawArc(oval, 0, 180, true, mWavePaint);
-
return;
-
}
-
// 绘制,即水面静止时的高度
-
RectF oval = new RectF(mScreenWidth / 4 + mRingSTROKEWidth / 2,
-
mScreenHeight / 4 + mRingSTROKEWidth / 2 + mAmplitude * 2,
-
mScreenWidth * 3 / 4 - mRingSTROKEWidth / 2, mScreenHeight * 3
-
/ 4 - mRingSTROKEWidth / 2);// 设置个新的长方形,扫描测量
-
canvas.drawArc(oval, 0, 180, true, mWavePaint);
-
-
if (this.c >= 8388607L) {
-
this.c = 0L;
-
}
-
// 每次onDraw时c都会自增
-
c = (1L + c);
-
float f1 = mScreenHeight * (1.0F - mWateLevel);
-
int top = (int) (f1 + mAmplitude);
-
mPath.reset();
-
int startX = mScreenWidth / 2 - mScreenWidth / 4 + mRingSTROKEWidth / 2;
-
// 波浪效果
-
while (startX < mScreenWidth / 2 + mScreenWidth / 4 - mRingSTROKEWidth
-
/ 2) {
-
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.restore();
-
}
-
-
@Override
-
public Parcelable onSaveInstanceState() {
-
// Force our ancestor class to save its state
-
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];
-
}
-
};
-
}
-
-
}
github下载地址: