最近公司一个项目需要实现仿微信拍照,然后我去看了看微信的界面:

然后我自己最后实现的界面是这样:

当然,这个界面不是重点,重点是这个自定义View需要实现单击实现拍照,长按实现录制视频。然后这个自定义View可以通过自定义触摸事件来完成区别。其实一开始我也不明白,为什么按下去的时候就开始调用了长按监听事件,最后还能将二者区分。最后留意到这一句代码:

myHandler.sendEmptyMessageDelayed(0, animTime);//animTime默认值是200;

其中表达的意思是该信息将在200毫秒后发送出去,我们看看手指抬起后的处理:

case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:startTime = 0;float upX = event.getX();float upY = event.getY();if(myHandler.hasMessages(0)){myHandler.removeMessages(0);if (Math.abs(upX - downX) < dp5 && Math.abs(upY - downY) < dp5) {if(onGestureListener != null) onGestureListener.onClick();}}else if(onGestureListener != null && closeMode){onGestureListener.onLift();closeButton();}break;

如果myHandler还有这条消息没有处理(拍照的情况)就移除,并调用点击的监听事件;如果没有这条消息了(录制视频的情况)就调用手指离开的监听,并且通过closeButton()方法来初始化控件,整个手势处理就这么简单,代码如下:

package cn.com.vicent.mymap;import android.animation.ValueAnimator;
import android.content.Context;
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.util.Log;
import android.view.MotionEvent;
import android.view.View;/*** Created by asus on 2017/4/22.*/public class RecordedButton extends View {private static final String TAG = "RecordedButton";private int measuredWidth = -1;private Paint paint;private int colorGray;private float radius1;private float radius2;private float zoom = 0.7f;//初始化缩放比例private int dp5;private Paint paintProgress;private int colorBlue;private float girth;//周长private RectF oval;private int max;private OnGestureListener onGestureListener;private int animTime = 200;private float downX;private float downY;private boolean closeMode = true;public RecordedButton(Context context) {super(context);init();}public RecordedButton(Context context, AttributeSet attrs) {super(context, attrs);init();}public RecordedButton(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {dp5 = (int) getResources().getDimension(R.dimen.dp5);colorGray = getResources().getColor(R.color.gray);colorBlue = getResources().getColor(R.color.blue);paint = new Paint();paint.setAntiAlias(true);paintProgress = new Paint();paintProgress.setAntiAlias(true);paintProgress.setColor(colorBlue);paintProgress.setStrokeWidth(dp5);paintProgress.setStyle(Paint.Style.STROKE);}public interface OnGestureListener {void onLongClick();void onClick();void onLift();void onOver();}public void setOnGestureListener(OnGestureListener onGestureListener){this.onGestureListener = onGestureListener;}private Handler myHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {if(onGestureListener != null) {startAnim(0, 1-zoom);onGestureListener.onLongClick();closeMode = true;}}};@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()){case MotionEvent.ACTION_DOWN:myHandler.sendEmptyMessageDelayed(0, animTime);downX = event.getX();downY = event.getY();break;case MotionEvent.ACTION_MOVE:break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:float upX = event.getX();float upY = event.getY();if(myHandler.hasMessages(0)){myHandler.removeMessages(0);if (Math.abs(upX - downX) < dp5 && Math.abs(upY - downY) < dp5) {if(onGestureListener != null) onGestureListener.onClick();}}else if(onGestureListener != null && closeMode){onGestureListener.onLift();closeButton();}break;}return true;}public void closeButton(){if(closeMode) {closeMode = false;startAnim(1 - zoom, 0);girth = 0;invalidate();}}private void startAnim(float start, float end){ValueAnimator va = ValueAnimator.ofFloat(start, end).setDuration(animTime);va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float value = (float) animation.getAnimatedValue();radius1 = measuredWidth * (zoom + value) / 2;radius2 = measuredWidth * (zoom - value) / 2.5f;invalidate();}});va.start();}public void setMax(int max){this.max = max;}public void setProgress(float progress){float ratio = progress/max;girth = 370*ratio;invalidate();if(ratio >= 1){if(onGestureListener != null) onGestureListener.onOver();}}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);if(measuredWidth == -1) {measuredWidth = getMeasuredWidth();// radius1:radius2 = 5:4radius1 = measuredWidth* zoom /2;radius2 = measuredWidth* zoom /2.5f;//设置绘制大小 边距2.5dpoval = new RectF();oval.left = dp5/2;oval.top = dp5/2;oval.right = measuredWidth-dp5/2;oval.bottom = measuredWidth-dp5/2;}}@Overrideprotected void onDraw(Canvas canvas) {//绘制外圈圆 radius1代表绘制半径paint.setColor(colorGray);canvas.drawCircle(measuredWidth/2, measuredWidth/2, radius1, paint);//绘制内圈圆 radius2代表绘制半径paint.setColor(Color.WHITE);canvas.drawCircle(measuredWidth/2, measuredWidth/2, radius2, paint);Log.d(TAG, "onDraw: "+radius1+"   "+radius2);//绘制进度 270表示以圆的270度为起点, 绘制girth长度的弧线canvas.drawArc(oval, 270, girth, false, paintProgress);}
}

使用的也比较简单,没有一个自定义属性,所以实例化控件之后简单的设定一下录制视频的最长时间和具体的监听事件实现就好!

  final RecordedButton recordedButton = (RecordedButton) findViewById(R.id.btn);recordedButton.setMax(30*1000);//最长录制时间30秒Timer timer = new Timer();//通过timer来模拟拍摄的进度recordedButton.setOnGestureListener(new RecordedButton.OnGestureListener() {@Overridepublic void onLongClick() {//长按监听final long startTime = System.currentTimeMillis();timer.schedule(new TimerTask() {@Overridepublic void run() {runOnUiThread(new Runnable() {@Overridepublic void run() {long progress = System.currentTimeMillis()-startTime;recordedButton.setProgress(progress);//默认的进度值是0,所以这个需要自定义}});}},1000,1000);}@Overridepublic void onClick() {
timer.cancel();}@Overridepublic void onLift() {
timer.cancel();}@Overridepublic void onOver() {
timer.cancel();}});

如果这里的进度值只是时间的话,其实我们还可以直接在控件里面来实现,将控件的功能封装得更好,于是修改代码如下:

private boolean closeMode = false;
private long startTime;@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()){case MotionEvent.ACTION_DOWN:startTime = System.currentTimeMillis();myHandler.sendEmptyMessageDelayed(0, animTime);downX = event.getX();downY = event.getY();break;case MotionEvent.ACTION_MOVE:break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:startTime = 0;float upX = event.getX();float upY = event.getY();if(myHandler.hasMessages(0)){myHandler.removeMessages(0);if (Math.abs(upX - downX) < dp5 && Math.abs(upY - downY) < dp5) {if(onGestureListener != null) onGestureListener.onClick();}}else if(onGestureListener != null && closeMode){onGestureListener.onLift();closeButton();}break;}return true;}private Handler myHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {if(onGestureListener != null) {startAnim(0, 1-zoom);onGestureListener.onLongClick();closeMode = true;if(!closeMode){setProgress(System.currentTimeMillis()-startTime);myHandler.sendEmptyMessageDelayed(0, 50);}}}};public void setProgress(float progress){float ratio = progress/max;girth = 370*ratio;invalidate();if(ratio >= 1){if(onGestureListener != null) onGestureListener.onOver();}}

OK,这个功能就实现了!

学习的源码

仿微信录制视频之自定义View相关推荐

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

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

  2. Android自定义view之仿微信录制视频按钮

    本文章只写了个类似微信的录制视频的按钮,效果图如下:            一.主要的功能: 1.长按显示进度条,单击事件,录制完成回调 2.最大时间和最小时间控制 3.进度条宽度,颜色设置 二.实现 ...

  3. android仿微信雷达 头像效果 自定义view

    ScreeningRadarView public class ScreeningRadarView extends View {// 定义画笔Paint paint;float radiusDiff ...

  4. Android录制视频,仿微信小视频录制(一)

    Android录制视频,第一部分自定义控件 简述 公司有一个录制视频并上传的功能,录制视频具体使用类如下:硬件控制使用Camera,视频录制的格式音频等具体配置与录制使用MediaRecorder,预 ...

  5. Android 仿微信录制短视频(不使用 FFmpeg)

    转载请标明出处与作者:https://blog.csdn.net/u011133887/article/details/83654724 项目中原本就有录制短视频的功能,使用的是 # qdrzwd/V ...

  6. Android仿微信录制短视频

    WxRecoderVideo 简介 基于VCamera,Android仿微信录制短视频,如果喜欢请star,如果觉得有纰漏请提交issue,如果你有更好的点子可以提交pull request. 使用 ...

  7. android高仿微信小视频,Android仿微信录制小视频

    本文实例为大家分享了Android仿微信录制小视频的具体代码,供大家参考,具体内容如下 先上张图片看看效果 简单叙述下 首先通过Camera类调用系统相机 通过surfaceview绘制出来 通过Me ...

  8. Android仿微信小视频录制功能(二)

    Android仿微信小视频录制功能(二) 接着上一篇,在完成了录制功能后,伟大的哲学家沃兹基索德曾经说过:"有录就有放.",那么紧接着就来实现播放功能,按照国际惯例,先上下效果图: ...

  9. 基于VCamera,仿微信录制短视频

    基于VCamera,Android仿微信录制短视频,如果喜欢请star,如果觉得有纰漏请提交issue,如果你有更好的点子可以提交pull request. recoder4.gif 使用 1) 在b ...

最新文章

  1. 《人月神话》——外科手术队伍——笔记!
  2. 面试官:private修饰的方法可以通过反射访问,那么private的意义是什么?
  3. 20.27分发系统介绍;20.28expect脚本远程登录;20.29expect脚本远程执行命令;20.30expect脚本传递参数...
  4. 为什么淘宝、天猫和旺信的 App 不整合成一个?
  5. 正则表达式过滤HTML危险脚本
  6. 一站式VDI部署教程(3)配置存储分层和重复数据删除功能
  7. ios怎样在一个UIImageButton的里面加一些自己定义的箭头
  8. mongodb php代码实例,php操作mongoDB实例分析
  9. SecureRandom-随机数的生成
  10. LeetCode 排序和搜索简单部分 Python实现
  11. python基础代码技巧_写Python必须知道的这几个代码技巧!你会吗?
  12. windows 使用 tricks
  13. java时间格式转换
  14. Delta并联机构在ADAMS仿真中的运动副设置
  15. JAVA实现ECC加密 eclipse
  16. [转]移动App测试中的最佳做法
  17. Unity播放广告切到后台,返回Unity广告消失问题
  18. 纸浆暴力反弹——复制去年走势,铁矿石认购2-4倍,双硅价差再度翘尾?2022.6.28
  19. Echarts水滴图
  20. Oracle 11g安装报错

热门文章

  1. 内存调试 - MEMWATCH
  2. 联通设置4g信号显示无服务器,一眼辨明联通网络字母标识 看懂手机是怎么显示2G/3G/4G的...
  3. 物联网应用中的 Wi-Fi 6
  4. xcode请求日志在哪里看_iOS日志获取和实时浏览器显示日志
  5. html提交重置按钮居中,html中如何让提交按钮居中?
  6. kismet一款用于进行wifi监听的软件
  7. 2022年有哪些降噪耳机?高性价比降噪耳机推荐
  8. 代码工程/Qt 开发环境提升(2)
  9. 【基础】Flink -- Time and Window
  10. loongarch架构的统信UOS+银河麒麟系统盘制作