Android 分享一个流量显示界面

时间:2021-09-30 10:17:28
版本:1.0 日期:2014.8.9 2014.9.24版权:© 2014 kince 转载注明出处  
  波形效果有几种不同的呈现形式,比如从中间向四周散开的波形,也就是熟知的水涟漪;还有上下波动的曲线,像五线谱等。英文中可以称作Wave或者Ripple,所以暂且叫它们WaveView、WaveLayout、RippleView、RippleLayout,接下来开始实现这些效果。  首先看一下Solo 火爆足球动态壁纸,Android 分享一个流量显示界面
  下面中间的按钮就是一个波形按钮,它会不断地向四周辐射,由于是静态图,如果想体验真实效果可以另行下载。这种效果的实现思路是不断绘制圆形,当然半径也要不断变化,透明度也是一样。代码如下:
/***
*/
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);
}

}
  下图是某个应用的流量显示界面,使用的是上面说的第二种形式。Android 分享一个流量显示界面  实现上面效果的思路是使用正弦或者余弦曲线,代码如下:
/****/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下载地址:
https://github.com/wangjinyu501/RippleViewhttps://github.com/wangjinyu501/WaterWaveView/
                                                                                                                                                                




相关文章