Android 自定义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 = ;
/**默认最大的进度*/
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,仿微信视频播放按钮的更多相关文章
- Android自定义View——仿滴滴出行十大司机评选活动说明
滴滴出行原版图 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 仿图 ? ? ? ? ? ? 1.分 ...
- android自定义View之仿通讯录侧边栏滑动,实现A-Z字母检索
我们的手机通讯录一般都有这样的效果,如下图: OK,这种效果大家都见得多了,基本上所有的android手机通讯录都有这样的效果.那我们今天就来看看这个效果该怎么实现. 一.概述 1.页面功能分析 整体 ...
- Android自定义View(LimitScrollerView-仿天猫广告栏上下滚动效果)
转载请标明出处: http://blog.csdn.net/xmxkf/article/details/53303872 本文出自:[openXu的博客] 1分析 2定义组合控件布局 3继承最外层控件 ...
- Android 自定义View合集
自定义控件学习 https://github.com/GcsSloop/AndroidNote/tree/master/CustomView 小良自定义控件合集 https://github.com/ ...
- Android 自定义 View 圆形进度条总结
Android 自定义圆形进度条总结 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 微信公众号:牙锅子 源码:CircleProgress 文中如有纰漏,欢迎大家留言指出. 最近 ...
- 简单说说Android自定义view学习推荐的方式
这几天比较受关注,挺开心的,嘿嘿. 这里给大家总结一下学习自定义view的一些技巧. 以后写自定义view可能不会写博客了,但是可以开源的我会把源码丢到github上我的地址:https://git ...
- Android自定义View之ProgressBar出场记
关于自定义View,我们前面已经有三篇文章在介绍了,如果筒子们还没阅读,建议先看一下,分别是android自定义View之钟表诞生记.android自定义View之仿通讯录侧边栏滑动,实现A-Z字母检 ...
- android自定义View之NotePad出鞘记
现在我们的手机上基本都会有一个记事本,用起来倒也还算方便,记事本这种东东,如果我想要自己实现,该怎么做呢?今天我们就通过自定义View的方式来自定义一个记事本.OK,废话不多说,先来看看效果图. 整个 ...
- android 自定义view 前的基础知识
本篇文章是自己自学自定义view前的准备,具体参考资料来自 Android LayoutInflater原理分析,带你一步步深入了解View(一) Android视图绘制流程完全解析,带你一步步深入了 ...
随机推荐
- 使用Log Explorer查看和恢复数据
由于一次意外操作,把QC数据库中的BUG表数据给删掉了.崩溃-上网找了下恢复方法,找到一款Log Explorer.下载安装使用后,发现这款软件的确不错,收藏ing. 本次的使用的Log Expl ...
- cnblog评价以及团队软件的部分改善
博客评价: 1.在word2003版本里的东西复制,不能直接直接粘贴到博客发表(发生过,大部分时候可以): 2.第一次使用的时候不知道复制过来的代码都是左对齐的,(代码排版和插入图片位置不明显): 3 ...
- win8.1 cygwin编译java轻量虚拟机avian
1.背景 昨天在网上看到别人用aauto写本地小程序写的很爽,我觉得如果java的jre能小一点,凭借java庞大的第三方类库写小工具也还算不错的.本人就经常用eclipse+一些commons包写些 ...
- MySQL自动化安装(双主多从读写分离)
shell #!/bin/bash # Create by # version 1.0 # // # # check out lockfile whether or not exist IsInput ...
- 学习Linux第六天
1.Shell编程 bash变量: 都是以字符串格式存储 x=5 等号左右不能有空格,会当作命令处理 如何调用: echo $x 此法无法进行数值运算,不存在的变量输出空 set -u 设置变量报错 ...
- 面向对象版js分页
基于前一个js分页,我将代码改成一个面向对象版的js分页,代码如下 http://peng666.github.io/blogs/pageobj <!DOCTYPE html> <h ...
- JS 学习笔记--4---运算符
1.JS 中包含的运算符有:一元运算符.二元运算符.三元运算符.算术运算符.关系运算符.逻辑运算符.位运算符.赋值运算符.其他的运算符等. 2.表达式:简单来讲就是一句代码(分号隔开),解释器会把它翻 ...
- Leetcode#150 Evaluate Reverse Polish Notation
原题地址 基本栈操作. 注意数字有可能是负的. 代码: int toInteger(string &s) { ; ] == '-' ? true : false; : ; i < s.l ...
- BZOJ 3714: [PA2014]Kuglarz
Description 魔术师的桌子上有n个杯子排成一行,编号为1,2,-,n,其中某些杯子底下藏有一个小球,如果你准确地猜出是哪些杯子,你就可以获得奖品.花费c_ij元,魔术师就会告诉你杯子i,i+ ...
- libxml2 crash
在 xmlParseFile 就那么挂在里面了 只有一个dll 和一堆头文件 没法调试 有如下猜想(感谢fb 和 array) 这是一个unhandled exception可以catch看看 也许是 ...