闲着,尝试实现了新版微信视频播放按钮,使用的是自定义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 = ;
/**默认最大的进度*/
private static final int DEFAULT_MAX_PROGRESS=;
/**描边宽度*/
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,);
} 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, , 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))/-mStrokeWidth;
//计算进度圆的半径,减去两倍描边宽度,作为进度圆和外圆环之间的间隙
mInnerRiadius =mOutRadius-*mStrokeWidth;
//确定进度圆的范围
mProgressOval = new RectF(mWidth / - mInnerRiadius, mHeight /
- mInnerRiadius, mWidth / + mInnerRiadius, mHeight
/ + mInnerRiadius); int triangleHeight = mOutRadius/;
//用三个点来确定三角形的位置,这里以外圆环直径的1/3作为三角形的水平方向的高度,
//水平方向向右做了 1/2高度的偏移,让三角形中心与圆的中心重叠(从视觉上来说是中心了,从科学的角度来讲这里应该不是中心,博主数学基础不扎实。。)
mTriangle = new Path();
mTriangle.moveTo(w/-triangleHeight/,w/-triangleHeight);
mTriangle.lineTo(w/+triangleHeight+triangleHeight/,h/);
mTriangle.lineTo(w/-triangleHeight/,w/+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/,mHeight/,mOutRadius,mStrokePaint);
if (mCurrentState==ProgressState.RUNNING) {//运行状态,绘制进度圆
canvas.drawArc(mProgressOval,-,(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 * / 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 = ;
private int mProgress = ;
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();
}
}
};
mDownloadThread.start();
}
isStop=false;
} @Override
public void onPause(int percent) {//暂停
isStop=true;
} @Override
public void onCompletely() {
Toast.makeText(MainActivity.this, "完成", ).show();
} @Override
public void onCompletedClick() {//缓冲完成之后点击播放
Toast.makeText(MainActivity.this, "播放", ).show();
} };
}
}

Android 自定义View,仿微信视频播放按钮的更多相关文章

  1. Android自定义View——仿滴滴出行十大司机评选活动说明

    滴滴出行原版图 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 仿图 ? ? ? ? ? ? 1.分 ...

  2. android自定义View之仿通讯录侧边栏滑动,实现A-Z字母检索

    我们的手机通讯录一般都有这样的效果,如下图: OK,这种效果大家都见得多了,基本上所有的android手机通讯录都有这样的效果.那我们今天就来看看这个效果该怎么实现. 一.概述 1.页面功能分析 整体 ...

  3. Android自定义View(LimitScrollerView-仿天猫广告栏上下滚动效果)

    转载请标明出处: http://blog.csdn.net/xmxkf/article/details/53303872 本文出自:[openXu的博客] 1分析 2定义组合控件布局 3继承最外层控件 ...

  4. Android 自定义View合集

    自定义控件学习 https://github.com/GcsSloop/AndroidNote/tree/master/CustomView 小良自定义控件合集 https://github.com/ ...

  5. Android 自定义 View 圆形进度条总结

    Android 自定义圆形进度条总结 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 微信公众号:牙锅子 源码:CircleProgress 文中如有纰漏,欢迎大家留言指出. 最近 ...

  6. 简单说说Android自定义view学习推荐的方式

    这几天比较受关注,挺开心的,嘿嘿. 这里给大家总结一下学习自定义view的一些技巧.  以后写自定义view可能不会写博客了,但是可以开源的我会把源码丢到github上我的地址:https://git ...

  7. Android自定义View之ProgressBar出场记

    关于自定义View,我们前面已经有三篇文章在介绍了,如果筒子们还没阅读,建议先看一下,分别是android自定义View之钟表诞生记.android自定义View之仿通讯录侧边栏滑动,实现A-Z字母检 ...

  8. android自定义View之NotePad出鞘记

    现在我们的手机上基本都会有一个记事本,用起来倒也还算方便,记事本这种东东,如果我想要自己实现,该怎么做呢?今天我们就通过自定义View的方式来自定义一个记事本.OK,废话不多说,先来看看效果图. 整个 ...

  9. android 自定义view 前的基础知识

    本篇文章是自己自学自定义view前的准备,具体参考资料来自 Android LayoutInflater原理分析,带你一步步深入了解View(一) Android视图绘制流程完全解析,带你一步步深入了 ...

随机推荐

  1. LintCode-BackPack II

    Given n items with size A[i] and value V[i], and a backpack with size m. What's the maximum value ca ...

  2. Netsharp快速入门(之1) 介绍及需求说明

    作者:秋时 杨昶   时间:2014-02-15  转载须说明出处 第一章 快速入门介绍 Netsharp是一个企业基础业务管理平台,介绍Netsharp分三个系列,分别是: 1.         N ...

  3. fwrite ,fprintf的作用与区别

    1.概念和作用 fwrite是C语言函数,指向文件写入一个数据块,写入的是 fprintf是C/C++中的一个格式化写-库函数,其作用是格式输出到一个流/文件中:原型是int fprintf( FIL ...

  4. 配置Symfony2

    安装成功后打开server php app/console server:run 127.0.0.1:8000 然后在浏览器输入localhost/8000/config.php进行配置 1.date ...

  5. github/gitlab 管理多个ssh key

    github/gitlab 管理多个ssh key 以前只使用一个 ssh key 在github上提交代码,由于工作原因,需要再添加一个ssh key在公司的 gitlab上提交代码,下面记录下配置 ...

  6. 剑指offer--面试题20

    题目:从外向里顺时针打印矩阵 做题心得:该题本质上并未考查复杂的数据结构及算法,而是考查了快速找规律的能力!!! 要想作出此题,必须先有绝对清晰的思路,否则越写越乱(因为涉及到很多的循环打印) 自己当 ...

  7. Spring Mvc 返回机制

    转自:http://jianzh5.iteye.com/blog/1909234 Spring Mvc 有如下的几种返回方式: ModelAndView, Model, ModelMap, Map, ...

  8. 封装dll遇到的奇葩错误:error LNK2005: _DllMain@12 已经在 DLLMain.obj 中定义

    在定义一个dll工程的时候,一添加MFC的头文件就会报出这个 错误:error LNK2005: _DllMain@12 已经在 DLLMain.obj 中定义  既蛋疼又蛋疼!! 然后逛论坛,查资料 ...

  9. asp.net 创建文字特效

    相信word 中的 艺术字 功能大家都不陌生.今天, 我们就利用C#来制作几款自己的艺术字, 可能会对我们了解字体图像的制作原理有一些帮助. 至于有没有使用价值我保持沉默. 一. 投影效果 程序运行效 ...

  10. KafkaClient接口与Kafka处理请求的若干特性

    (依据于0.10.0.0版本) 这个接口的唯一实现类就是NetworkClient,它被用于实现Kafka的consumer和producer. 这个接口实际上抽象出来了Kafka client与网络 ...