刚好有注意到百度外卖以及淘宝个人中心,都用到了类似水波起伏的效果,于是就参照网上的资料然后自己整改,自定义了一个waveView ,原理么,首先就是自定义个WaveView,继承View,然后再WaveView 内部实现代码逻辑:
自定义WaveView
public class LD_WaveView extends View {
private int mProgress;//进度
private int mTimeStep = 10;//时间间隔
private int mSpeed = 5;//波单次移动的距离
private int mViewHeight;//视图宽高
private int mViewWidth;//视图宽度
private int mLevelLine;// 基准线
private int mWaveLength;//波长 暂定view宽度为一个波长
private int mStrokeWidth;//园的线宽
private RectF rectF;//圆环区域
private int mWaveHeight;//波峰高度
private int mLeftWaveMoveLength;//波平移的距离,用来控制波的起点位置
private int mWaveColor;//波的颜色
private Paint mPaint;//画笔
private Paint mCirclePaint;//圆环画笔
private Paint mBorderPaint;//边界画笔
private int mBorderWidth=4;//边界宽度
private Paint mTextPaint;//文字画笔
private Path mPath;//绘画线
private List<Point> mPoints;//点的集合
private boolean isMeasure = false;//是否已测量过
private boolean isCircle=false;//是否圆形默认false,可属性代码设置 //处理消息
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
initWaveMove(); }
};
/** * 初始化波的移动 */
private void initWaveMove(){
mLeftWaveMoveLength+=mSpeed;//波向右移动距离增加mSpeed;
if (mLeftWaveMoveLength>=mWaveLength){
//当增加到一个波长时回复到0
mLeftWaveMoveLength=0;
}
invalidate();
}
public LD_WaveView(Context context) { this(context, null); }
public LD_WaveView(Context context, AttributeSet attrs) { this(context, attrs, 0); }
public LD_WaveView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
getAttr(context, attrs, defStyleAttr);
init();
}
/** * 初始化画笔 */
private void init() {
mPoints = new ArrayList<Point>(); //波浪轨迹画笔
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(mWaveColor);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPath = new Path(); //文字画笔
mTextPaint=new Paint();
mTextPaint.setColor(Color.RED);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mTextPaint.setTextSize(48); //圆环画笔
mCirclePaint=new Paint();
mCirclePaint.setAntiAlias(true);
mCirclePaint.setColor(Color.WHITE);
mCirclePaint.setStyle(Paint.Style.STROKE); //边界线画笔
mBorderPaint=new Paint();
mBorderPaint.setAntiAlias(true);
mBorderPaint.setColor(mWaveColor);
mBorderPaint.setStrokeWidth(mBorderWidth); mBorderPaint.setStyle(Paint.Style.STROKE); }
/** * 获取自定义的属性值 * * @param attrs */
private void getAttr(Context context, AttributeSet attrs, int defStyle) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LD_WaveView, defStyle, 0);
mWaveColor = a.getColor(R.styleable.LD_WaveView_wave_color, Color.RED); isCircle=a.getBoolean(R.styleable.LD_WaveView_wave_circle,false); a.recycle(); }
/** * * @param widthMeasureSpec * @param heightMeasureSpec */
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (!isMeasure&&Math.abs(getMeasuredHeight()-getMeasuredWidth())<50) {
//只计算一次就够了 ,relativelayout的时候要绘制两次 加个宽高判断
mViewHeight = getMeasuredHeight();
mViewWidth = getMeasuredWidth();
mLevelLine = mViewHeight;
//初始化波的准位线 起始位视图最底部
{
mLevelLine = mViewHeight * (100-mProgress) / 100;
if (mLevelLine < 0)
mLevelLine = 0;
}
//计算波峰值
mWaveHeight = mViewHeight / 20;
//波峰暂定为view高度的1/20,如果需要设置 可设置set方法赋值;
mWaveLength = getMeasuredWidth();
//计算所有的点 这里取宽度为整个波长 往左再延伸一个波长 两个波长则需要9个点
for (int i = 0; i < 9; i++) {
int y = 0;
switch (i % 4) {
case 0:
y = mViewHeight;
break;
case 1:
y =mViewHeight+ mWaveHeight;
break;
case 2:
y = mViewHeight;
break;
case 3:
y = mViewHeight-mWaveHeight;
break;
}
Point point = new Point(-mWaveLength + i * mWaveLength / 4, y);
mPoints.add(point); }
/** * 计算圆环宽度 */
int mIncircleRadius=mViewHeight<mViewWidth?mViewHeight/2:mViewWidth/2;
//内切圆半径
int mcircumcircleRadius= (int) (Math.sqrt((float)(Math.pow(mViewHeight/2,2)+Math.pow(mViewWidth/2,2)))+0.5);
//外接圆半径
int radius=mcircumcircleRadius/2+mIncircleRadius/2;
rectF=new RectF(mViewWidth/2-radius,mViewHeight/2-radius,mViewWidth/2+radius,mViewHeight/2+radius); mStrokeWidth=mcircumcircleRadius-mIncircleRadius; mCirclePaint.setStrokeWidth(mStrokeWidth);
//线是有宽度的 采用了这种方式画圆环 isMeasure = true; } }
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/** * 绘制线条 */
mPath.reset();
int i = 0;
mPath.moveTo(mPoints.get(0).getX()+mLeftWaveMoveLength, mPoints.get(0).getY()-mViewHeight*mProgress/100);
for (; i < mPoints.size() - 2; i += 2) {
mPath.quadTo(mPoints.get(i + 1).getX()+mLeftWaveMoveLength, mPoints.get(i + 1).getY()-mViewHeight*mProgress/100, mPoints.get(i + 2).getX()+mLeftWaveMoveLength, mPoints.get(i + 2).getY()-mViewHeight*mProgress/100);
}
mPath.lineTo(mPoints.get(i).getX()+mLeftWaveMoveLength, mViewHeight); mPath.lineTo(mPoints.get(0).getX()+mLeftWaveMoveLength, mViewHeight);
mPath.close();
/** * 绘制轨迹 */
canvas.drawPath(mPath,mPaint);
Rect rect = new Rect();
String progress=String.format("%d%%",mProgress); mTextPaint.getTextBounds(progress,0,progress.length(), rect);
int textHeight = rect.height();
if (mProgress>=50)
//如果进度达到50 颜色变为白色,没办法啊,进度在中间 不变颜色看不到 mTextPaint.setColor(Color.WHITE);
else mTextPaint.setColor(mWaveColor); canvas.drawText(progress,0,progress.length(),mViewWidth/2,mViewHeight/2+textHeight/2,mTextPaint);
if (isCircle) {
/** * 绘制圆环 */
canvas.drawArc(rectF, 0, 360, true, mCirclePaint);
Paint circlePaint = new Paint();
circlePaint.setStrokeWidth(5);
circlePaint.setColor(Color.WHITE);
circlePaint.setAntiAlias(true);
circlePaint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(mViewWidth / 2, mViewHeight / 2, mViewHeight / 2, circlePaint);
/** * 绘制边界 */
mBorderPaint.setStrokeWidth(mBorderWidth/2);
canvas.drawCircle(mViewWidth/2,mViewHeight/2,mViewHeight/2-mBorderWidth/2,mBorderPaint);
}
else {
/** * 绘制矩形边框 */
canvas.drawRect(0,0,mViewWidth,mViewHeight,mBorderPaint);
}
handler.sendEmptyMessageDelayed(0,mTimeStep);
}
/** * 设置进度 基准线 *
@param mProgress */
public void setmProgress(int mProgress) {
this.mProgress = mProgress;
mLevelLine=(100-mProgress)*mViewHeight/100;
}
/** * 设置是否为圆形 * @param circle */
public void setCircle(boolean circle) { isCircle = circle; }}
自定义属性
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="LD_WaveView">
<attr name="wave_color" format="color"></attr>
<attr name="wave_circle" format="boolean"></attr>
</declare-styleable>
</resources>
xml布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:orientation="vertical">
<com.zx.android_01.WaveView
android:id="@+id/waveViewCircle"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
app:wave_circle="true"
app:wave_color="#000000" />
<com.zx.android_01.WaveView
android:id="@+id/waveView"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true"
app:wave_circle="false"
app:wave_color="#000000" />
</RelativeLayout>
调用的Activity
public class MainActivity extends AppCompatActivity {
WaveView waveView;//方形
WaveView waveCircleView;//圆形
private int progrees = 0;//进度
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (progrees == 100)
progrees = 0;
Log.i("progress", progrees + "");
waveView.setmProgress(progrees++);
waveCircleView.setmProgress(progrees++);
mHandler.sendEmptyMessageDelayed(0, 100);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
waveView = (WaveView) findViewById(R.id.waveView);
waveCircleView = (WaveView) findViewById(R.id.waveViewCircle);
mHandler.sendEmptyMessageDelayed(0, 10);
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
}
}