本文章只写了个类似微信的录制视频的按钮,效果图如下:

          

一、主要的功能:

1.长按显示进度条,单击事件,录制完成回调

2.最大时间和最小时间控制

3.进度条宽度,颜色设置

二、实现思路

该自定义View主要有三块组成,白色内圆,浅色大圆,圆形进度条;长按一段时间,内圆缩小0.75倍,外圆放大1.33倍,进度条显示更新,松开手内圆,外圆统一恢复到原来大小;长按时间达到最大,影藏进度条,,同样内圆外圆恢复到原来大小;动画主要用到属性动画中的ValueAnimator,在一定时间内匀速改变内圆,外圆半径,和圆形进度条的绘制角度,最后调用invalidate()重新绘制,起到动画的作用。

三、代码分析

@Overrideprotected void onDraw(final Canvas canvas) {super.onDraw(canvas);//绘制外圆canvas.drawCircle(mWidth/2,mHeight/2,mBigRadius,mBigCirclePaint);//绘制内圆canvas.drawCircle(mWidth/2,mHeight/2,mSmallRadius,mSmallCirclePaint);//录制的过程中绘制进度条if(isRecording){drawProgress(canvas);}}

绘制内外圆,isRecording表示录制的情况下才参与绘制,相当于显示

@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()){case MotionEvent.ACTION_DOWN:isPressed=true;mStartTime=System.currentTimeMillis();Message mMessage=Message.obtain();mMessage.what=WHAT_LONG_CLICK;mHandler.sendMessageDelayed(mMessage,mLongClickTime);break;case MotionEvent.ACTION_UP:isPressed=false;isRecording=false;mEndTime=System.currentTimeMillis();if(mEndTime-mStartTime<mLongClickTime){mHandler.removeMessages(WHAT_LONG_CLICK);if(onClickListener!=null)onClickListener.onClick();}else{startAnimation(mBigRadius,mInitBitRadius,mSmallRadius,mInitSmallRadius);//手指离开时动画复原if(mProgressAni!=null&&mProgressAni.getCurrentPlayTime()/1000<mMinTime&&!isMaxTime){if(onLongClickListener!=null){onLongClickListener.onNoMinRecord(mMinTime);}mProgressAni.cancel();}else{//录制完成if(onLongClickListener!=null&&!isMaxTime){onLongClickListener.onRecordFinishedListener();}}}break;}return true;}

长按的事件是通过handler发送延时消息实现的,按下的时候就发送,当手指离开,记录按下和离开的时间间隔,达到一定时间即为长按,否则直接移除消息,长按事件失效,此时情况就是点击事件;


private Handler mHandler=new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what){case WHAT_LONG_CLICK://长按事件触发if(onLongClickListener!=null) {onLongClickListener.onLongClick();}//内外圆动画,内圆缩小,外圆放大startAnimation(mBigRadius,mBigRadius*1.33f,mSmallRadius,mSmallRadius*0.7f);break;}}} ;

handler里面处理的即为长按的触发事件,此时开始startAnimation

private void startAnimation(float bigStart,float bigEnd, float smallStart,float smallEnd) {ValueAnimator bigObjAni=ValueAnimator.ofFloat(bigStart,bigEnd);bigObjAni.setDuration(150);bigObjAni.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {mBigRadius= (float) animation.getAnimatedValue();invalidate();}});ValueAnimator smallObjAni=ValueAnimator.ofFloat(smallStart,smallEnd);smallObjAni.setDuration(150);smallObjAni.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {mSmallRadius= (float) animation.getAnimatedValue();invalidate();}});bigObjAni.start();smallObjAni.start();smallObjAni.addListener(new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(Animator animation) {isRecording=false;}@Overridepublic void onAnimationEnd(Animator animation) {//开始绘制圆形进度if(isPressed){isRecording=true;isMaxTime=false;startProgressAnimation();}}@Overridepublic void onAnimationCancel(Animator animation) {}@Overridepublic void onAnimationRepeat(Animator animation) {}});}

ValueAnimator.ofFloat(bigStart,bigEnd);让圆的半径从bigStart到bigEnd动态变化,

设置addUpdateListener监听,获取正在变化的值重新赋值给圆的半径,调用 invalidate重新绘制,从而起到动画的效果,在开始录制的动画结束后,来绘制圆形进度条,

/*** 绘制圆形进度* @param canvas*/private void drawProgress(Canvas canvas) {mProgressCirclePaint.setStrokeWidth(mProgressW);mProgressCirclePaint.setStyle(Paint.Style.STROKE);//用于定义的圆弧的形状和大小的界限RectF oval = new RectF(mWidth/2-(mBigRadius-mProgressW/2), mHeight/2-(mBigRadius-mProgressW/2), mWidth/2+(mBigRadius-mProgressW/2),mHeight/2+(mBigRadius-mProgressW/2));//根据进度画圆弧canvas.drawArc(oval, -90, mCurrentProgress, false, mProgressCirclePaint);}

RectF限制圆弧的绘制范围,mCurrentProgress绘制的角度0~360f之间变化,同样可以利用ValueAnimator,来在0~360f之间不断改变,然后不断更新绘制,起到进度条动态更新的效果

四、全部代码

package com.yus.ycamera;import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;/*** Created by yufs on 2017/7/4.*/public class CircleButtonView extends View{private static final int WHAT_LONG_CLICK = 1;private Paint mBigCirclePaint;private Paint mSmallCirclePaint;private Paint mProgressCirclePaint;private int mHeight;//当前View的高private int mWidth;//当前View的宽private float mInitBitRadius;private float mInitSmallRadius;private float mBigRadius;private float mSmallRadius;private long mStartTime;private long mEndTime;private Context mContext;private boolean isRecording;//录制状态private boolean isMaxTime;//达到最大录制时间private float mCurrentProgress;//当前进度private long mLongClickTime=500;//长按最短时间(毫秒),private int mTime=5;//录制最大时间sprivate int mMinTime=3;//录制最短时间private int mProgressColor;//进度条颜色private float mProgressW=18f;//圆环宽度private boolean isPressed;//当前手指处于按压状态private ValueAnimator mProgressAni;//圆弧进度变化public CircleButtonView(Context context ) {super(context);init(context,null);}public CircleButtonView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context,attrs);}public CircleButtonView(Context context, AttributeSet attrs) {super(context, attrs);init(context,attrs);}private void init(Context context,AttributeSet attrs) {this.mContext=context;TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleButtonView);mMinTime=a.getInt(R.styleable.CircleButtonView_minTime,0);mTime=a.getInt(R.styleable.CircleButtonView_maxTime,10);mProgressW=a.getDimension(R.styleable.CircleButtonView_progressWidth,12f);mProgressColor=a.getColor(R.styleable.CircleButtonView_progressColor,Color.parseColor("#6ABF66"));a.recycle();//初始画笔抗锯齿、颜色mBigCirclePaint=new Paint(Paint.ANTI_ALIAS_FLAG);mBigCirclePaint.setColor(Color.parseColor("#DDDDDD"));mSmallCirclePaint=new Paint(Paint.ANTI_ALIAS_FLAG);mSmallCirclePaint.setColor(Color.parseColor("#FFFFFF"));mProgressCirclePaint=new Paint(Paint.ANTI_ALIAS_FLAG);mProgressCirclePaint.setColor(mProgressColor);mProgressAni= ValueAnimator.ofFloat(0, 360f);mProgressAni.setDuration(mTime*1000);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mWidth = MeasureSpec.getSize(widthMeasureSpec);mHeight=MeasureSpec.getSize(heightMeasureSpec);mInitBitRadius=mBigRadius= mWidth/2*0.75f;mInitSmallRadius=mSmallRadius= mBigRadius*0.75f;}@Overrideprotected void onDraw(final Canvas canvas) {super.onDraw(canvas);//绘制外圆canvas.drawCircle(mWidth/2,mHeight/2,mBigRadius,mBigCirclePaint);//绘制内圆canvas.drawCircle(mWidth/2,mHeight/2,mSmallRadius,mSmallCirclePaint);//录制的过程中绘制进度条if(isRecording){drawProgress(canvas);}}/*** 绘制圆形进度* @param canvas*/private void drawProgress(Canvas canvas) {mProgressCirclePaint.setStrokeWidth(mProgressW);mProgressCirclePaint.setStyle(Paint.Style.STROKE);//用于定义的圆弧的形状和大小的界限RectF oval = new RectF(mWidth/2-(mBigRadius-mProgressW/2), mHeight/2-(mBigRadius-mProgressW/2), mWidth/2+(mBigRadius-mProgressW/2),mHeight/2+(mBigRadius-mProgressW/2));//根据进度画圆弧canvas.drawArc(oval, -90, mCurrentProgress, false, mProgressCirclePaint);}private Handler mHandler=new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what){case WHAT_LONG_CLICK://长按事件触发if(onLongClickListener!=null) {onLongClickListener.onLongClick();}//内外圆动画,内圆缩小,外圆放大startAnimation(mBigRadius,mBigRadius*1.33f,mSmallRadius,mSmallRadius*0.7f);break;}}} ;@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()){case MotionEvent.ACTION_DOWN:isPressed=true;mStartTime=System.currentTimeMillis();Message mMessage=Message.obtain();mMessage.what=WHAT_LONG_CLICK;mHandler.sendMessageDelayed(mMessage,mLongClickTime);break;case MotionEvent.ACTION_UP:isPressed=false;isRecording=false;mEndTime=System.currentTimeMillis();if(mEndTime-mStartTime<mLongClickTime){mHandler.removeMessages(WHAT_LONG_CLICK);if(onClickListener!=null)onClickListener.onClick();}else{startAnimation(mBigRadius,mInitBitRadius,mSmallRadius,mInitSmallRadius);//手指离开时动画复原if(mProgressAni!=null&&mProgressAni.getCurrentPlayTime()/1000<mMinTime&&!isMaxTime){if(onLongClickListener!=null){onLongClickListener.onNoMinRecord(mMinTime);}mProgressAni.cancel();}else{//录制完成if(onLongClickListener!=null&&!isMaxTime){onLongClickListener.onRecordFinishedListener();}}}break;}return true;}private void startAnimation(float bigStart,float bigEnd, float smallStart,float smallEnd) {ValueAnimator bigObjAni=ValueAnimator.ofFloat(bigStart,bigEnd);bigObjAni.setDuration(150);bigObjAni.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {mBigRadius= (float) animation.getAnimatedValue();invalidate();}});ValueAnimator smallObjAni=ValueAnimator.ofFloat(smallStart,smallEnd);smallObjAni.setDuration(150);smallObjAni.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {mSmallRadius= (float) animation.getAnimatedValue();invalidate();}});bigObjAni.start();smallObjAni.start();smallObjAni.addListener(new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(Animator animation) {isRecording=false;}@Overridepublic void onAnimationEnd(Animator animation) {//开始绘制圆形进度if(isPressed){isRecording=true;isMaxTime=false;startProgressAnimation();}}@Overridepublic void onAnimationCancel(Animator animation) {}@Overridepublic void onAnimationRepeat(Animator animation) {}});}/*** 圆形进度变化动画*/private void startProgressAnimation() {mProgressAni.start();mProgressAni.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {mCurrentProgress= (float) animation.getAnimatedValue();invalidate();}});mProgressAni.addListener(new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(Animator animation) {}@Overridepublic void onAnimationEnd(Animator animation) {//录制动画结束时,即为录制全部完成if(onLongClickListener!=null&&isPressed){isPressed=false;isMaxTime=true;onLongClickListener.onRecordFinishedListener();startAnimation(mBigRadius,mInitBitRadius,mSmallRadius,mInitSmallRadius);//影藏进度进度条mCurrentProgress=0;invalidate();}}@Overridepublic void onAnimationCancel(Animator animation) {}@Overridepublic void onAnimationRepeat(Animator animation) {}});}/*** 长按监听器*/public interface OnLongClickListener{void onLongClick();//未达到最小录制时间void onNoMinRecord(int currentTime);//录制完成void onRecordFinishedListener();}public OnLongClickListener onLongClickListener;public void setOnLongClickListener(OnLongClickListener onLongClickListener) {this.onLongClickListener = onLongClickListener;}/*** 点击监听器*/public interface OnClickListener{void onClick();}public OnClickListener onClickListener;public void setOnClickListener(OnClickListener onClickListener) {this.onClickListener = onClickListener;}}

属性文件

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="CircleButtonView"><attr name="minTime" format="integer"></attr><attr name="maxTime" format="integer"></attr><attr name="progressColor" format="color"></attr><attr name="progressWidth" format="dimension"></attr></declare-styleable>
</resources>

全部的大家可以下载源码查看,有什么问题,欢迎提出,后续会将此控件应用到小视频的录制上面,下一遍记录小视频录制,还有就是个人在demo演示的时候都没有找到个将视频转gif的,上面也只能贴图片,哎,心塞

源码

Android自定义view之仿微信录制视频按钮相关推荐

  1. Android自定义View分享——仿微信朋友圈图片合并效果

    写在前面 笔者近来在学习Android自定义View,收集了一些不算复杂但又"长得"还可以的自定义View效果实现,之前分享过两个效果:一个水平的进度条,一个圆形温度显示器,如果你 ...

  2. android 自定义取色器,【Android自定义View】仿Photoshop取色器ColorPicker(二)

    ColorPicker 一款仿Photoshop取色器的Android版取色器. 前言 上一篇已经简单介绍了ColorPicker的项目结构以及两种颜色空间,接下来我们详细解析一下ColorPicke ...

  3. 仿微信录制视频和拍照并发送留言

    仿微信小视频录制功能,打开相机后,点击是拍照,长按是录制,录制小于1秒,要提示"录制时间太短",最大可以录制1分钟的视频,拍完照或录制完视频后,要自动跳转到相片或视频展示页面,点击 ...

  4. Android自定义View之仿QQ运动步数进度效果

    文章目录 前言 先看效果图 ![在这里插入图片描述](https://img-blog.csdnimg.cn/6e4ddec17933496ea4830fa08d8ffbe5.png?x-oss-pr ...

  5. Android自定义view之仿支付宝芝麻信用仪表盘 ---by ccy

    自定义view练习 仿支付宝芝麻信用的仪表盘 对比图: 首先是自定义一些属性,可自己再添加,挺基础的,上代码 <?xml version="1.0" encoding=&qu ...

  6. 自定义xy组 android,Android自定义view之仿支付宝芝麻信用仪表盘示例

    自定义view练习 仿支付宝芝麻信用的仪表盘 对比图: 首先是自定义一些属性,可自己再添加,挺基础的,上代码 接着在构造方法里初始化自定义属性和画笔: private void initAttr(At ...

  7. Android自定义View分享——仿网易云音乐留声机效果

    写在前面 这是笔者自学习自定义View以来,分享的第五篇效果,之前分享过一篇动态时钟效果的自定义View,如果有兴趣的可以看看: Android自定义View分享--一个时钟 之前的博客笔者一般都会说 ...

  8. 仿微信录制视频之自定义View

    最近公司一个项目需要实现仿微信拍照,然后我去看了看微信的界面: 然后我自己最后实现的界面是这样: 当然,这个界面不是重点,重点是这个自定义View需要实现单击实现拍照,长按实现录制视频.然后这个自定义 ...

  9. Android自定义ListView实现仿微信侧滑删除

    经常在遇到问题第一时间都会在网上搜索解决的方法,因此看到很多前辈们的比较精辟的技术文章,学习了很多东西,现在将自己平时工作中开发的一些小功能坐下总结,也写出来,既方便自己理清思路记忆功能块实现思路,又 ...

最新文章

  1. 《塞洛特傳說》道具系统
  2. python使用符号 表示单行注释-Pyhton 单行、多行注释符号使用方法及规范
  3. Jmeter接口测试进阶
  4. Union-Find 并查集算法详解
  5. 应行家算法_一些行家技巧和窍门
  6. prometheus命令_Prometheus入门教程(一):Prometheus 快速入门
  7. 618电商大促 到底谁家赢了?大家都这么有钱的吗?
  8. GPS导航电文编码与校验
  9. Arduino 超声波避障循迹小车,四轮智能小车
  10. 质量管理体系五大核心工具
  11. python音频 降噪_一种基于深度神经网络的音频降噪方法技术
  12. 计算机提示策略阻止安装,win7安装软件提示此程序被组策略阻止怎么办
  13. 网线/双绞线相关知识
  14. Exp7 网络欺诈防范 20164302 王一帆
  15. 高漫数位板1060PRO 8192级的驱动下载与安装
  16. 企业邮箱如何发送国外邮件?2021知名企业邮箱网站排名
  17. 为什么装完计算机系统后进不去,电脑系统装完后为啥进不去?
  18. 文件共享服务器onedrive,如何共享OneDrive文件和文件夹
  19. MD5算法的编程实现
  20. ubuntu16.04的HDMI没有输出不能外接显示器

热门文章

  1. SQL 查询中exists用法
  2. 电脑打开计算机的管理闪退怎么办,电脑软件打开后闪退或崩溃的解决办法
  3. 火狐浏览器打开时会自动打开毒霸网址大全
  4. ubuntu如何挂载硬盘
  5. Jetson TX1内核kernel编译与烧写
  6. OmniPlayer Pro for Mac(全能多媒体播放器)
  7. 300字的计算机英语作文,【实用】英语作文300字四篇
  8. 【公告】关于开启用户注册及登录手机短信验证的通知
  9. 数电学习(七、半导体存储器)
  10. AI癌症检测 手机拍照就能检测肿瘤,也太牛了吧