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 Prototype对象
Jan 07 Javascript
javascript之querySelector和querySelectorAll使用说明
Oct 09 Javascript
Jquery遍历checkbox获取选中项value值的方法
Feb 13 Javascript
javascript实现的右下角弹窗实例
Apr 24 Javascript
JS建造者模式基本用法实例分析
Jun 30 Javascript
js 自带的sort() 方法全面了解
Aug 16 Javascript
HTML5开发Kinect体感游戏的实例应用
Sep 18 Javascript
Vue精简版风格概述
Jan 30 Javascript
vue中动态绑定表单元素的属性方法
Feb 23 Javascript
详解webpack4升级指南以及从webpack3.x迁移
Jun 12 Javascript
Vue axios与Go Frame后端框架的Options请求跨域问题详解
Mar 03 Javascript
JavaScript实现网页计算器功能
Oct 29 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
人工智能开始玩《星际争霸2》 你的操作跟得上吗?
2017/08/11 星际争霸
落伍首发 php+mysql 采用ajax技术的 省 市 地 3级联动无刷新菜单 源码
2006/12/16 PHP
PHP如何编写易读的代码
2007/07/10 PHP
php中static静态变量的使用方法详解
2010/06/04 PHP
PHP常用特殊运算符号和函数总结(php新手入门必看)
2013/02/02 PHP
php的数组与字符串的转换函数整理汇总
2013/07/18 PHP
destoon复制新模块的方法
2014/06/21 PHP
PHP获取网页所有连接的方法(附demo源码下载)
2016/03/30 PHP
JQERY limittext 插件0.2版(长内容限制显示)
2010/08/27 Javascript
jquery 跳到顶部和底部动画2句代码简单实现
2013/07/18 Javascript
js、jquery图片动画、动态切换示例代码
2014/06/03 Javascript
JS实现动画兼容性的transition和transform实例分析
2016/12/13 Javascript
原生Aajax 和jQuery Ajax 写法个人总结
2017/03/24 jQuery
详解webpack进阶之插件篇
2017/07/06 Javascript
原生JS控制多个滚动条同步跟随滚动效果
2017/12/22 Javascript
vue-cli脚手架build目录下utils.js工具配置文件详解
2018/09/14 Javascript
element el-input directive数字进行控制
2018/10/11 Javascript
从零使用TypeScript开发项目打包发布到npm
2020/02/14 Javascript
小程序跳转到的H5页面再跳转回跳小程序的方法
2020/03/06 Javascript
Python实现的监测服务器硬盘使用率脚本分享
2014/11/07 Python
Python的Flask框架中Flask-Admin库的简单入门指引
2015/04/07 Python
Python自定义函数计算给定日期是该年第几天的方法示例
2019/05/30 Python
Selenium元素定位的30种方式(史上最全)
2020/05/11 Python
浅析python字符串前加r、f、u、l 的区别
2021/01/24 Python
Pytorch模型迁移和迁移学习,导入部分模型参数的操作
2021/03/03 Python
教师的实习自我鉴定
2013/12/17 职场文书
工程业务员岗位职责
2013/12/31 职场文书
做一个有道德的人活动实施方案
2014/08/23 职场文书
大学生党员学习焦裕禄精神思想汇报
2014/09/10 职场文书
教师党员整改措施
2014/10/24 职场文书
2015年汽车销售工作总结
2015/04/07 职场文书
小学教育见习总结
2015/06/23 职场文书
情感电台广播稿
2015/08/18 职场文书
2016优秀教师先进个人事迹材料
2016/02/25 职场文书
Windows下用Nginx配置https服务器及反向代理的问题
2021/09/25 Servers
git stash(储藏)的用法总结
2022/06/25 Servers