package com.lwd.playbutton;
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.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.View.OnClickListener;/**
* 仿微信视频播放按钮
* @author Vitor Lee*/
public classPlayButton extends View implements OnClickListener {/**默认最大角度*/
private static final int DEFAULT_MAX_ANGLE = 360;/**默认最大的进度*/
private static final int DEFAULT_MAX_PROGRESS=100;/**描边宽度*/
private intmStrokeWidth;/**外圆环半径*/
private intmOutRadius;/**内圆半径*/
private intmInnerRiadius;/**控件的宽度*/
private intmWidth;/**控件的高度*/
private intmHeight;/**描边的画笔*/
privatePaint mStrokePaint;/**实心画笔*/
privatePaint mFillPaint;/**进度圆的*/
privateRectF mProgressOval;/**最大进度*/
private int mMax=DEFAULT_MAX_PROGRESS;/**当前进度*/
private intmProgress;/**三角形的路径*/
privatePath mTriangle;private ProgressState mCurrentState=ProgressState.PRE_START;publicPlayButton(Context context) {this(context,null);
}publicPlayButton(Context context, AttributeSet attrs) {this(context, attrs,0);
}public PlayButton(Context context, AttributeSet attrs, intdefStyle) {
super(context, attrs, defStyle);
initParams();
initAttribute(context, attrs, defStyle);
}private voidinitParams() {
mStrokeWidth= (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP,1, getResources()
.getDisplayMetrics());//初始化描边的笔
mStrokePaint = newPaint(Paint.ANTI_ALIAS_FLAG);
mStrokePaint.setColor(Color.WHITE);
mStrokePaint.setStyle(Paint.Style.STROKE);
mStrokePaint.setStrokeWidth(mStrokeWidth);//初始化画实心的笔
mFillPaint = newPaint(Paint.ANTI_ALIAS_FLAG);
mFillPaint.setColor(Color.WHITE);
mFillPaint.setStyle(Paint.Style.FILL);
setOnClickListener(this);
}private void initAttribute(Context context, AttributeSet attrs, intdefStyle) {//TODO 增加自定义属性,解析应用自定义属性
}
@Overrideprotected void onSizeChanged(int w, int h, int oldw, intoldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth=w;
mHeight=h;//计算外环的半径 得到控件宽高的最小值作为圆的半径,还要减去掉描边的宽度
mOutRadius = (Math.min(w, h))/2-mStrokeWidth;//计算进度圆的半径,减去两倍描边宽度,作为进度圆和外圆环之间的间隙
mInnerRiadius =mOutRadius-2*mStrokeWidth;//确定进度圆的范围
mProgressOval = new RectF(mWidth / 2 - mInnerRiadius, mHeight / 2
- mInnerRiadius, mWidth / 2 +mInnerRiadius, mHeight/ 2 +mInnerRiadius);int triangleHeight = mOutRadius/3;//用三个点来确定三角形的位置,这里以外圆环直径的1/3作为三角形的水平方向的高度,//水平方向向右做了 1/2高度的偏移,让三角形中心与圆的中心重叠(从视觉上来说是中心了,从科学的角度来讲这里应该不是中心,博主数学基础不扎实。。)
mTriangle = newPath();
mTriangle.moveTo(w/2-triangleHeight/2,w/2-triangleHeight);
mTriangle.lineTo(w/2+triangleHeight+triangleHeight/2,h/2);
mTriangle.lineTo(w/2-triangleHeight/2,w/2+triangleHeight);
mTriangle.close();//等边三角形//mRantange = new Path();//float halfOfRantangeHeight = (float) (Math.sqrt(1f/27*Math.pow(mOutRadius*2,2)));//Log.e("xxx","mOutRadius/3="+mOutRadius/3+" ,halfOfRantangeHeight="+halfOfRantangeHeight);//mRantange.moveTo(w/2-mOutRadius/6,h/2-halfOfRantangeHeight);//mRantange.lineTo(w/2+mOutRadius/3+mOutRadius/6,h/2);//mRantange.lineTo(w/2-mOutRadius/6,h/2+halfOfRantangeHeight);//mRantange.close();
}
@Overrideprotected voidonDraw(Canvas canvas) {//绘制外圆环
canvas.drawCircle(mWidth/2,mHeight/2,mOutRadius,mStrokePaint);if (mCurrentState==ProgressState.RUNNING) {//运行状态,绘制进度圆
canvas.drawArc(mProgressOval,-90,(mProgress*1f/mMax*DEFAULT_MAX_ANGLE),true,mFillPaint);
}else{//非运行状态画三角形
canvas.drawPath(mTriangle,mStrokePaint);
}
}
@Overridepublic voidonClick(View v) {switch(mCurrentState) {casePRE_START:if (listener != null) {
listener.onStart();
}
mCurrentState=ProgressState.RUNNING;break;caseRUNNING:if (listener != null) {
listener.onPause(mProgress* 100 /mMax);
}
mCurrentState=ProgressState.PAUSE;
invalidate();break;casePAUSE:if (listener != null) {
listener.onStart();
}
mCurrentState=ProgressState.RUNNING;
invalidate();break;caseCOMPLETELY:if (listener!=null) {
listener.onCompletedClick();
}break;
}
}privateOnProgressClickListener listener;/**
* 设置最大值
* @param max 最大值*/
public void setMax(intmax){
mMax=max;
}/**
* 设置当前进度
* @param progress 当前进度*/
public void setProgress(intprogress){
mProgress=progress;if (mCurrentState!=ProgressState.RUNNING) {
mCurrentState=ProgressState.RUNNING;
}if (mProgress>=mMax) {
mCurrentState=ProgressState.COMPLETELY;if (listener!=null) {//进度圆完成回调
listener.onCompletely();
}
}
invalidate();
}/**
* 设置监听事件
* @param l 监听器*/
public voidsetOnProgressClickListener(OnProgressClickListener l) {this.listener =l;
}/**
* 这里提供了四个回调方法,比较多,可能只用到其中几个,
* 所以采用了抽象类来实现,除了必要的开始操作以外,
* 其他的操作用户需要哪个方法自己复写就行了。*/
public static abstract classOnProgressClickListener {/** 开始*/
public abstract voidonStart();/** 暂停*/
public void onPause(intpercent){};/** 结束*/
public voidonCompletely(){};/** 完成后点击*/
public voidonCompletedClick(){};
}/**控件状态*/
public enumProgressState{/**开始之前*/PRE_START,/**运行*/RUNNING,/**暂停*/PAUSE,/**完成*/COMPLETELY;
}
}