闲着,尝试实现了新版微信视频播放按钮,使用的是自定义View,先来个简单的效果图。。。真的很简单哈。
由于暂时用不到,加上时间原因,加上实在是没意思,加上……,本控件就没有实现自定义属性,有兴趣的朋友可以自己去添加一下,方法都给你们准备好了。- =
其实这个控件主要步骤
1、画外环的圆
2、画进度的圆或者画三角形播放按钮
其余剩下的都是围绕以上两步准备或者收尾的。
接下来贴主要我们的自定义控件代码,注释很全,我就不过多解释了,请各位看官自己分析,有疑问可以在评论区一起讨论。
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 class PlayButton extends View implements OnClickListener { /**默认最大角度*/ private static final int DEFAULT_MAX_ANGLE = 360; /**默认最大的进度*/ private static final int DEFAULT_MAX_PROGRESS=100; /**描边宽度*/ private int mStrokeWidth; /**外圆环半径*/ private int mOutRadius; /**内圆半径*/ private int mInnerRiadius; /**控件的宽度*/ private int mWidth; /**控件的高度*/ private int mHeight; /**描边的画笔*/ private Paint mStrokePaint; /**实心画笔*/ private Paint mFillPaint; /**进度圆的*/ private RectF mProgressOval; /**最大进度*/ private int mMax=DEFAULT_MAX_PROGRESS; /**当前进度*/ private int mProgress; /**三角形的路径*/ private Path mTriangle; private ProgressState mCurrentState=ProgressState.PRE_START; public PlayButton(Context context) { this(context,null); } public PlayButton(Context context, AttributeSet attrs) { this(context, attrs,0); } public PlayButton(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initParams(); initAttribute(context, attrs, defStyle); } private void initParams() { mStrokeWidth = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 1, getResources() .getDisplayMetrics()); //初始化描边的笔 mStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mStrokePaint.setColor(Color.WHITE); mStrokePaint.setStyle(Paint.Style.STROKE); mStrokePaint.setStrokeWidth(mStrokeWidth); //初始化画实心的笔 mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mFillPaint.setColor(Color.WHITE); mFillPaint.setStyle(Paint.Style.FILL); setOnClickListener(this); } private void initAttribute(Context context, AttributeSet attrs, int defStyle) { //TODO 增加自定义属性,解析应用自定义属性 } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { 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 = new Path(); 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(); } @Override protected void onDraw(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); } } @Override public void onClick(View v) { switch (mCurrentState) { case PRE_START: if (listener != null) { listener.onStart(); } mCurrentState = ProgressState.RUNNING; break; case RUNNING: if (listener != null) { listener.onPause(mProgress * 100 / mMax); } mCurrentState = ProgressState.PAUSE; invalidate(); break; case PAUSE: if (listener != null) { listener.onStart(); } mCurrentState = ProgressState.RUNNING; invalidate(); break; case COMPLETELY: if (listener!=null) { listener.onCompletedClick(); } break; } } private OnProgressClickListener listener; /** * 设置最大值 * @param max 最大值 */ public void setMax(int max){ mMax=max; } /** * 设置当前进度 * @param progress 当前进度 */ public void setProgress(int progress){ mProgress=progress; if (mCurrentState!=ProgressState.RUNNING) { mCurrentState=ProgressState.RUNNING; } if (mProgress>=mMax) { mCurrentState=ProgressState.COMPLETELY; if (listener!=null) {//进度圆完成回调 listener.onCompletely(); } } invalidate(); } /** * 设置监听事件 * @param l 监听器 */ public void setOnProgressClickListener(OnProgressClickListener l) { this.listener = l; } /** * 这里提供了四个回调方法,比较多,可能只用到其中几个, * 所以采用了抽象类来实现,除了必要的开始操作以外, * 其他的操作用户需要哪个方法自己复写就行了。 */ public static abstract class OnProgressClickListener { /** 开始 */ public abstract void onStart(); /** 暂停 */ public void onPause(int percent){}; /** 结束 */ public void onCompletely(){}; /** 完成后点击 */ public void onCompletedClick(){}; } /**控件状态*/ public enum ProgressState{ /**开始之前*/ PRE_START, /**运行*/ RUNNING, /**暂停*/ PAUSE, /**完成*/ COMPLETELY; } }
接下来我们说说怎么使用,现在xml中定义我们的自定义控件。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="${relativePackage}.${activityClass}" android:background="@android:color/black" > <com.lwd.playbutton.PlayButton android:id="@+id/buffer_button" android:layout_width="50dp" android:layout_height="50dp" /> </RelativeLayout>
然后我们在Activity中模拟一下缓冲视频,并且播放的操作。
package com.lwd.playbutton; import com.lwd.bufferbutton.R; import com.lwd.playbutton.PlayButton.OnProgressClickListener; import android.app.Activity; import android.os.Bundle; import android.os.SystemClock; import android.widget.Toast; /** * 模拟视频缓冲的activity * @author Vitor Lee */ public class MainActivity extends Activity { private static final int DEFAULT_MAX_VALUE = 100; private int mProgress = 0; private PlayButton mProgressView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mProgressView = (PlayButton) findViewById(R.id.buffer_button); mProgressView.setOnProgressClickListener(getProgressClickListener()); mProgressView.setMax(DEFAULT_MAX_VALUE); } private OnProgressClickListener getProgressClickListener() { return new OnProgressClickListener() { private Thread mDownloadThread; private boolean isStop; @Override public void onStart() {//模拟下载 if (mDownloadThread==null) { mDownloadThread = new Thread() { @Override public void run() { while (true) { if (!isStop) { runOnUiThread(new Runnable() { @Override public void run() { mProgressView.setProgress(mProgress); mProgress++; } }); if (mProgress==DEFAULT_MAX_VALUE) { break; } } SystemClock.sleep(100); } } }; mDownloadThread.start(); } isStop=false; } @Override public void onPause(int percent) {//暂停 isStop=true; } @Override public void onCompletely() { Toast.makeText(MainActivity.this, "完成", 1).show(); } @Override public void onCompletedClick() {//缓冲完成之后点击播放 Toast.makeText(MainActivity.this, "播放", 1).show(); } }; } }