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中通过URL传递汉字的方法
Apr 09 Javascript
JQuery给元素添加/删除节点比如select
Apr 02 Javascript
JavaScript插件化开发教程 (一)
Jan 27 Javascript
基于javascript实现图片切换效果
Apr 17 Javascript
javascript中对Date类型的常用操作小结
May 19 Javascript
jQuery插件EasyUI设置datagrid的checkbox为禁用状态的方法
Aug 05 Javascript
jQuery实现点击任意位置弹出层外关闭弹出层效果
Oct 19 Javascript
AngularJS学习第二篇 AngularJS依赖注入
Feb 13 Javascript
jQuery设置图片等比例缩小的方法
Apr 29 jQuery
Bootstrap弹出框之自定义悬停框标题、内容和样式示例代码
Jul 11 Javascript
vue 使某个组件不被 keep-alive 缓存的方法
Sep 21 Javascript
JavaScript, select标签元素左右移动功能实现
May 14 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
PHP中使用imagick生成PSD文件缩略图教程
2015/01/26 PHP
Zend Framework入门教程之Zend_View组件用法示例
2016/12/09 PHP
PHP实现Session入库/存入redis的方法
2017/05/04 PHP
yii2 在控制器中验证请求参数的使用方法
2019/06/19 PHP
PHP+Apache实现二级域名之间共享cookie的方法
2019/07/24 PHP
用javascript父窗口控制只弹出一个子窗口
2007/04/10 Javascript
Javascript中定义方法的另类写法(批量定义js对象的方法)
2011/02/25 Javascript
js遍历td tr等html元素
2012/12/13 Javascript
js将字符串转成正则表达式的实现方法
2013/11/13 Javascript
javascript修改IMG标签的src问题
2014/03/28 Javascript
jquery JSON的解析方式示例介绍
2014/07/27 Javascript
jquery幻灯片插件bxslider样式改进实例
2014/10/15 Javascript
全面了解JavaScript对象进阶
2016/07/19 Javascript
AngularJS 过滤器的简单实例
2016/07/27 Javascript
jQuery弹出div层过2秒自动消失
2016/11/29 Javascript
JavaScript奇技淫巧44招【实用】
2016/12/11 Javascript
canvas实现图像放大镜
2017/02/06 Javascript
原生JS轮播图插件
2017/02/09 Javascript
vue.js利用Object.defineProperty实现双向绑定
2017/03/09 Javascript
echart简介_动力节点Java学院整理
2017/08/11 Javascript
jQuery Validate插件ajax方式验证输入值的实例
2017/12/21 jQuery
vue2.0.js的多级联动选择器实现方法
2018/02/09 Javascript
vue-router中scrollBehavior的巧妙用法
2018/07/09 Javascript
webpack4实现不同的导出类型
2019/04/09 Javascript
javascript实现手动点赞效果
2019/04/09 Javascript
JQuery样式与属性设置方法分析
2019/12/07 jQuery
jquery实现商品sku多属性选择功能(商品详情页)
2019/12/20 jQuery
three.js利用射线Raycaster进行碰撞检测
2020/03/12 Javascript
Python基于Socket实现的简单聊天程序示例
2017/08/05 Python
Python+OpenCV采集本地摄像头的视频
2019/04/25 Python
python+opencv3生成一个自定义纯色图教程
2020/02/19 Python
Python图像处理库PIL中图像格式转换的实现
2020/02/26 Python
学前教育毕业生自荐信
2013/10/29 职场文书
统计岗位职责
2014/02/21 职场文书
医院员工辞职信范文
2015/05/12 职场文书
励志正能量20句:送给所有为梦想拼搏的人
2019/11/11 职场文书