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视图绘制流程完全解析,带你一步步深入了 ...
随机推荐
- Oracle EBS中查询Profile的各种SQL【转载】
1.List E-Business Suite Profile Option Values For All Levels SELECT p.profile_option_name SHORT_NAME ...
- Team Homework #2 Decide the roles of each team member ——IloveSE
大家好,我们是IloveSEers! 徐姗,我是一个性格开朗,但却认为计算机比较枯燥的女生.经过两年的学习,自己的编程能力,并不是很强,在这方便还需多多练习.对于软件工程这门课,我充满期待,因为我不仅 ...
- 30道小学生四则运算题C/C++编程
软件工程科课上,老师通过实例讲解什么是程序,程序和软件的区别,要求我们通过短时间写一道编程题, 题目就是编写30道小学生四则运算题.以下就是源代码: #include<iostream.h> ...
- android开发实现静默安装(fota升级)
这里只提供一个思路,也是咨询大神才了解到的. fota升级主要用于系统及系统应用的升级,不过貌似也会弹出提示用于用户确认.既然做到系统级别了,估计也一样可以静默安装的.
- Android入门视频推荐
marschen老师的Android入门视频推荐网址: 1.Android应用程序开发视频教程(重制版)第一季 2.Android应用开发视频教程(重制版)第二季 2.marschen老师的个人微 ...
- matrix_2015_1 138 - ZOJ Monthly, January 2015
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3844 第一个,n个数,每次操作最大数和最小数都变成他们的差值,最后n个数相 ...
- javascript中继承(二)-----借用构造函数继承的个人理解
本人目录如下: 零.寒暄&回顾 一,借用构造函数 二.事件代理 三,call和apply的用法 四.总结 零.寒暄&回顾 上次博客跟大家分享了自己对原型链继承的理解,想看的同学欢迎猛击 ...
- HDU1014Uniform Generator
Uniform Generator Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u ...
- TestDriven.Net
转: http://www.cnblogs.com/AlexLiu/archive/2008/12/01/1345002.html
- 一个奇怪的网络故障 默认网关为0.0.0.0(Windows)
用IPCONFIG命令看到的情况是这样: Windows IP 配置 以太网适配器 本地连接 : 连接特定的 DNS 后缀 . . . . . . . : 本地链接 IPv6 地址. . . . . ...