自定义View,仿微信视频播放按钮

闲着,尝试实现了新版微信视频播放按钮,使用的是自定义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();
			}
			
		};
	}
}
恩,没了。- =。上面就是完整的代码了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值