Android 自定义view仿微信相机单击拍照长按录视频按钮


Posted in Javascript onJuly 19, 2019

Android仿微信相机的拍照按钮单击拍照,长按录视频。先上效果图。

Android 自定义view仿微信相机单击拍照长按录视频按钮
Android 自定义view仿微信相机单击拍照长按录视频按钮

项目地址:https://github.com/c786909486/PhotoButton2/tree/v1.0

添加依赖

allprojects {
    repositories {
      ...
      maven { url 'https://jitpack.io' }
    }
  }

dependencies {
      compile compile 'com.github.c786909486:PhotoButton2:v1.1'
  }

长按效果分析

判断是否为长按,如果是,则扩大外圆,缩小内圆。由于要扩大外圆,所以在绘制常态的外圆时不可将圆的直径设置为view的宽度或高度。

outRoundPaint.setAntiAlias(true);
    outRoundPaint.setColor(outCircleColor);
    if (isLongClick){
      canvas.scale(1.2f,1.2f,width/2,height/2);
    }
    canvas.drawCircle(width/2,height/2, outRaduis, outRoundPaint);

if (isLongClick){
      canvas.drawCircle(width/2,height/2, innerRaduis /2.0f, innerRoundPaint);
      //画外原环
      mCPaint.setAntiAlias(true);
      mCPaint.setColor(progressColor);
      mCPaint.setStyle(Paint.Style.STROKE);
      mCPaint.setStrokeWidth(circleWidth/2);
      RectF rectF = new RectF(0+circleWidth,0+circleWidth,width-circleWidth,height-circleWidth);
      canvas.drawArc(rectF,startAngle,mSweepAngle,false,mCPaint);
    }else {
      canvas.drawCircle(width/2,height/2, innerRaduis, innerRoundPaint);
    }

然后通过手势识别判断单击、长按、长按抬起。

mDetector = new GestureDetectorCompat(context, new GestureDetector.SimpleOnGestureListener() {
      @Override
      public boolean onSingleTapConfirmed(MotionEvent e) {
        //单击
        isLongClick = false;
        if (listener != null) {
          listener.onClick(TakePhotoButton.this);
        }
        return super.onSingleTapConfirmed(e);
      }
      @Override
      public void onLongPress(MotionEvent e) {
        //长按
        isLongClick = true;
        postInvalidate();
        if (listener != null) {
          listener.onLongClick(TakePhotoButton.this);
        }
      }
    });
    mDetector.setIsLongpressEnabled(true);

 @Override
  public boolean onTouchEvent(MotionEvent event) {
    mDetector.onTouchEvent(event);
    switch(MotionEventCompat.getActionMasked(event)) {
      case MotionEvent.ACTION_DOWN:
        isLongClick = false;
        break;
      case MotionEvent.ACTION_UP:
      case MotionEvent.ACTION_CANCEL:
        if (isLongClick) {
          isLongClick = false;
          postInvalidate();
          if (this.listener != null) {
            this.listener.onLongClickUp(this);
          }
        }
        break;
    }
    return true;
  }

自定义接口对各个状态进行监听

public interface OnProgressTouchListener {
    /**
     * 单击
     * @param photoButton
     */
    void onClick(TakePhotoButton photoButton);
    /**
     * 长按
     * @param photoButton
     */
    void onLongClick(TakePhotoButton photoButton);
    /**
     * 长按抬起
     * @param photoButton
     */
    void onLongClickUp(TakePhotoButton photoButton);
    void onFinish();
  }

最后,给外圆弧添加动画

public void start() {
    ValueAnimator animator = ValueAnimator.ofFloat(mmSweepAngleStart, mmSweepAngleEnd);
    animator.setInterpolator(new LinearInterpolator());
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator valueAnimator) {
        mSweepAngle = (float) valueAnimator.getAnimatedValue();
        //获取到需要绘制的角度,重新绘制
        invalidate();
      }
    });
    //这里是时间获取和赋值
    ValueAnimator animator1 = ValueAnimator.ofInt(mLoadingTime, 0);
    animator1.setInterpolator(new LinearInterpolator());
    animator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator valueAnimator) {
        int time = (int) valueAnimator.getAnimatedValue();
      }
    });
    AnimatorSet set = new AnimatorSet();
    set.playTogether(animator, animator1);
    set.setDuration(mLoadingTime * 1000);
    set.setInterpolator(new LinearInterpolator());
    set.start();
    set.addListener(new AnimatorListenerAdapter() {
      @Override
      public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation);
        clearAnimation();
        isLongClick = false;
        postInvalidate();
        if (listener != null) {
          listener.onFinish();
        }
      }
    });
  }

最后,在activity中给控件设置监听即可。

buttontake.setOnProgressTouchListener(new TakePhotoButton.OnProgressTouchListener() {
      @Override
      public void onClick(TakePhotoButton photoButton) {
        Toast.makeText(MainActivity.this,"单机",Toast.LENGTH_SHORT).show();
      }
      @Override
      public void onLongClick(TakePhotoButton photoButton) {
        Toast.makeText(MainActivity.this,"长按",Toast.LENGTH_SHORT).show();
        buttontake.start();
      }
      @Override
      public void onLongClickUp(TakePhotoButton photoButton) {
        onFinish();
      }
      @Override
      public void onFinish() {
        Toast.makeText(MainActivity.this,"录制结束",Toast.LENGTH_SHORT).show();
      }
    });

        button.s

下面贴上完整的代码

TakePhotoButton:

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
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.support.annotation.Nullable;
import android.support.v4.view.GestureDetectorCompat;
import android.support.v4.view.MotionEventCompat;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.LinearInterpolator;
/**
 * Created by CKZ on 2017/8/9.
 */
public class TakePhotoButton extends View {
  private float circleWidth;//外圆环宽度
  private int outCircleColor;//外圆颜色
  private int innerCircleColor;//内圆颜色
  private int progressColor;//进度条颜色
  private Paint outRoundPaint = new Paint(); //外圆画笔
  private Paint mCPaint = new Paint();//进度画笔
  private Paint innerRoundPaint = new Paint();
  private float width; //自定义view的宽度
  private float height; //自定义view的高度
  private float outRaduis; //外圆半径
  private float innerRaduis;//内圆半径
  private GestureDetectorCompat mDetector;//手势识别
  private boolean isLongClick;//是否长按
  private float startAngle = -90;//开始角度
  private float mmSweepAngleStart = 0f;//起点
  private float mmSweepAngleEnd = 360f;//终点
  private float mSweepAngle;//扫过的角度
  private int mLoadingTime;
  public TakePhotoButton(Context context) {
    this(context,null);
}
  public TakePhotoButton(Context context, @Nullable AttributeSet attrs) {
    this(context, attrs,0);
  }
  public TakePhotoButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context,attrs);
  }
  private void init(Context context,AttributeSet attrs){
    TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.TakePhotoButton);
    outCircleColor = array.getColor(R.styleable.TakePhotoButton_outCircleColor,Color.parseColor("#E0E0E0"));
    innerCircleColor = array.getColor(R.styleable.TakePhotoButton_innerCircleColor,Color.WHITE);
    progressColor = array.getColor(R.styleable.TakePhotoButton_readColor,Color.GREEN);
    mLoadingTime = array.getInteger(R.styleable.TakePhotoButton_maxSeconds,10);
    mDetector = new GestureDetectorCompat(context, new GestureDetector.SimpleOnGestureListener() {
      @Override
      public boolean onSingleTapConfirmed(MotionEvent e) {
        //单击
        isLongClick = false;
        if (listener != null) {
          listener.onClick(TakePhotoButton.this);
        }
        return super.onSingleTapConfirmed(e);
      }
      @Override
      public void onLongPress(MotionEvent e) {
        //长按
        isLongClick = true;
        postInvalidate();
        if (listener != null) {
          listener.onLongClick(TakePhotoButton.this);
        }
      }
    });
    mDetector.setIsLongpressEnabled(true);
  }
  private void resetParams() {
    width = getWidth();
    height = getHeight();
    circleWidth = width*0.13f;
    outRaduis = (float) (Math.min(width, height)/2.4);
    innerRaduis = outRaduis -circleWidth;
  }
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    if (width > height) {
      setMeasuredDimension(height, height);
    } else {
      setMeasuredDimension(width, width);
    }
  }
  @Override
  protected void onDraw(Canvas canvas) {
    resetParams();
    //画外圆
    outRoundPaint.setAntiAlias(true);
    outRoundPaint.setColor(outCircleColor);
    if (isLongClick){
      canvas.scale(1.2f,1.2f,width/2,height/2);
    }
    canvas.drawCircle(width/2,height/2, outRaduis, outRoundPaint);
    //画内圆
    innerRoundPaint.setAntiAlias(true);
    innerRoundPaint.setColor(innerCircleColor);
    if (isLongClick){
      canvas.drawCircle(width/2,height/2, innerRaduis /2.0f, innerRoundPaint);
      //画外原环
      mCPaint.setAntiAlias(true);
      mCPaint.setColor(progressColor);
      mCPaint.setStyle(Paint.Style.STROKE);
      mCPaint.setStrokeWidth(circleWidth/2);
      RectF rectF = new RectF(0+circleWidth,0+circleWidth,width-circleWidth,height-circleWidth);
      canvas.drawArc(rectF,startAngle,mSweepAngle,false,mCPaint);
    }else {
      canvas.drawCircle(width/2,height/2, innerRaduis, innerRoundPaint);
    }
  }
  public void start() {
    ValueAnimator animator = ValueAnimator.ofFloat(mmSweepAngleStart, mmSweepAngleEnd);
    animator.setInterpolator(new LinearInterpolator());
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator valueAnimator) {
        mSweepAngle = (float) valueAnimator.getAnimatedValue();
        //获取到需要绘制的角度,重新绘制
        invalidate();
      }
    });
    //这里是时间获取和赋值
    ValueAnimator animator1 = ValueAnimator.ofInt(mLoadingTime, 0);
    animator1.setInterpolator(new LinearInterpolator());
    animator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator valueAnimator) {
        int time = (int) valueAnimator.getAnimatedValue();
      }
    });
    AnimatorSet set = new AnimatorSet();
    set.playTogether(animator, animator1);
    set.setDuration(mLoadingTime * 1000);
    set.setInterpolator(new LinearInterpolator());
    set.start();
    set.addListener(new AnimatorListenerAdapter() {
      @Override
      public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation);
        clearAnimation();
        isLongClick = false;
        postInvalidate();
        if (listener != null) {
          listener.onFinish();
        }
      }
    });
  }
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    mDetector.onTouchEvent(event);
    switch(MotionEventCompat.getActionMasked(event)) {
      case MotionEvent.ACTION_DOWN:
        isLongClick = false;
        break;
      case MotionEvent.ACTION_UP:
      case MotionEvent.ACTION_CANCEL:
        if (isLongClick) {
          isLongClick = false;
          postInvalidate();
          if (this.listener != null) {
            this.listener.onLongClickUp(this);
          }
        }
        break;
    }
    return true;
  }
  private OnProgressTouchListener listener;
  public void setOnProgressTouchListener(OnProgressTouchListener listener) {
    this.listener = listener;
  }
  /**
   * 进度触摸监听
   */
  public interface OnProgressTouchListener {
    /**
     * 单击
     * @param photoButton
     */
    void onClick(TakePhotoButton photoButton);
    /**
     * 长按
     * @param photoButton
     */
    void onLongClick(TakePhotoButton photoButton);
    /**
     * 长按抬起
     * @param photoButton
     */
    void onLongClickUp(TakePhotoButton photoButton);
    void onFinish();
  }
}

项目地址:https://github.com/c786909486/PhotoButton2/tree/v1.0

总结

以上所述是小编给大家介绍的Android 自定义view仿微信相机单击拍照长按录视频按钮,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

Javascript 相关文章推荐
JavaScript 数组循环引起的思考
Jan 01 Javascript
JavaScript 编写匿名函数的几种方法
Feb 21 Javascript
jQuery父级以及同级元素查找介绍
Sep 04 Javascript
js借助ActiveXObject实现创建文件
Sep 29 Javascript
使用Js让Html中特殊字符不被转义
Nov 05 Javascript
轻松实现javascript图片轮播特效
Jan 13 Javascript
详解使用Vue.Js结合Jquery Ajax加载数据的两种方式
Jan 10 Javascript
Javascript 使用ajax与C#获取文件大小实例详解
Jan 13 Javascript
JavaScript递归算法生成树形菜单
Aug 15 Javascript
vue项目中应用ueditor自定义上传按钮功能
Apr 27 Javascript
bootstrap-table实现表头固定以及列固定的方法示例
Mar 07 Javascript
15个简单的JS编码标准让你的代码更整洁(小结)
Jul 16 Javascript
使用element-ui的el-menu导航选中后刷新页面保持当前选中状态
Jul 19 #Javascript
Vue实战教程之仿肯德基宅急送App
Jul 19 #Javascript
微信小程序 扭蛋抽奖机css3动画实现详解
Jul 19 #Javascript
Vue配置marked链接添加target="_blank"的方法
Jul 19 #Javascript
vue-cli 项目打包完成后运行文件路径报错问题
Jul 19 #Javascript
Smartour 让网页导览变得更简单(推荐)
Jul 19 #Javascript
bootstrap Table实现合并相同行
Jul 19 #Javascript
You might like
ThinkPHP使用心得分享-ThinkPHP + Ajax 实现2级联动下拉菜单
2014/05/15 PHP
PHP编辑器PhpStrom运行缓慢问题
2017/02/21 PHP
laravel 框架结合关联查询 when()用法分析
2019/11/22 PHP
解决 FireFox 下[使用event很麻烦] 的问题.
2006/08/22 Javascript
jquery 模板的应用示例
2013/11/12 Javascript
jQuery实现带动画效果的二级下拉导航方法
2015/03/11 Javascript
JS随机调用指定函数的方法
2015/07/01 Javascript
jQuery实现模拟marquee标签效果
2015/07/14 Javascript
Jquery easyui 实现动态树
2015/11/17 Javascript
讲解JavaScript的Backbone.js框架的MVC结构设计理念
2016/02/14 Javascript
JS实现图片的不间断连续滚动的简单实例
2016/06/03 Javascript
javascript 正则表达式去空行方法
2017/01/24 Javascript
网页中的图片查看器viewjs使用方法
2017/07/11 Javascript
使用JavaScript实现链表的数据结构的代码
2017/08/02 Javascript
20170918 前端开发周报之JS前端开发必看
2017/09/18 Javascript
Vue-cli 使用json server在本地模拟请求数据的示例代码
2017/11/02 Javascript
angular json对象push到数组中的方法
2018/02/27 Javascript
Vue执行方法,方法获取data值,设置data值,方法传值操作
2020/08/05 Javascript
javascript实现时间日期的格式化的方法汇总
2020/08/06 Javascript
Python translator使用实例
2008/09/06 Python
Python基于动态规划算法计算单词距离
2015/07/25 Python
[原创]pip和pygal的安装实例教程
2017/12/07 Python
Django 使用Ajax进行前后台交互的示例讲解
2018/05/28 Python
30秒学会30个超实用Python代码片段【收藏版】
2019/10/15 Python
Laura Geller官网:美国彩妆品牌
2018/12/29 全球购物
高级方案规划工程师岗位职责
2013/11/29 职场文书
办公室文书岗位职责
2013/12/16 职场文书
体育专业学生自我评价范文
2014/01/17 职场文书
幼儿园开学家长寄语
2014/01/19 职场文书
光信息科学与技术专业职业生涯规划
2014/03/13 职场文书
我的中国梦演讲稿初中篇
2014/08/19 职场文书
2014年度个人工作总结范文
2015/03/09 职场文书
感恩父母主题班会
2015/08/12 职场文书
2016会计专业自荐信范文
2016/01/28 职场文书
管理者们如何制定2019年的工作计划?
2019/07/01 职场文书
python实现自动化群控的步骤
2021/04/11 Python