Android自定义View(短视频录制按钮)

2020-09-14  本文已影响0人  火星移民局局长

1,分析效果

image.png

1,控件由一个圆和一个逐步完善的圆环构成
2,圆环启示角度为270
3,按下按钮,圆环开始逐步完善,且录制事件开始
4,手指抬起,圆环停止完善;且录制事件停止
5,圆环满足360°录制事件停止

2,资源属性定义

  <declare-styleable name="VideoTakeButton">
        <attr name="cBackColor" format="color"/>//按钮的背景色
        <attr name="oInColor" format="color"/>//圆环的背景色
        <attr name="durTime" format="integer"/>//圆环完成一圈需要的事件
        <attr name="rangWidth" format="dimension"/>//圆环的宽度
    </declare-styleable>

3,开始编码

1.获取定义的属性参数

  private int cBackColor;//中间按钮的背景
    private int oInColor;//外环转动圆环的填充色
    private long durTime;//圆环转动一圈持续的时间
    private float rangWidth;//走动的圆环宽度


        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.VideoTakeButton);
        cBackColor = typedArray.getColor(R.styleable.VideoTakeButton_cBackColor, R.color.colorPrimary);
        oInColor = typedArray.getColor(R.styleable.VideoTakeButton_oInColor, R.color.colorPrimary);
        durTime = typedArray.getInt(R.styleable.VideoTakeButton_durTime, 10000);
        rangWidth = typedArray.getDimension(R.styleable.VideoTakeButton_rangWidth, 10);

2.初始化画笔

        cBtnPaint = new Paint();
        cBtnPaint.setColor(cBackColor);
        cBtnPaint.setStyle(Paint.Style.FILL);
        cBtnPaint.setAntiAlias(true);

        oCPaint = new Paint();
        oCPaint.setColor(oInColor);
        oCPaint.setStrokeWidth(rangWidth);
        oCPaint.setStyle(Paint.Style.STROKE);
        oCPaint.setAntiAlias(true);

3.测量控件大小

 int measureDimension(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        switch (specMode) {
            case MeasureSpec.AT_MOST:
                result = 100;
                break;

            case MeasureSpec.UNSPECIFIED:
            case MeasureSpec.EXACTLY:
                result = specSize;
                break;

        }
        return result;
    }

4.绘制控件

  canvas.drawCircle(getWidth() / 2, getHeight() / 2, Math.min(getWidth(), getHeight()) / 2 - rangWidth - rangAndCirPadding, cBtnPaint);
//圆的半径=控件布局-圆环的宽度-与圆环的边距
     
float sweepAngle;
//绘制
canvas.drawArc(rangWidth / 2, rangWidth / 2, getWidth() - rangWidth / 2, getHeight() - rangWidth / 2, 270, sweepAngle, false, oCPaint);
//需要逐步修改sweepAngle值重新绘制完成动画效果使用ValueAnimator
private void start() {
      ValueAnimator   valueAnimator = ValueAnimator.ofFloat(360f);
        valueAnimator.setDuration(durTime);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                sweepAngle = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        valueAnimator.start();
    }
   

5.触摸事件

  @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //手指按下
                if (isOnClickCnnter(event.getX(), event.getY()) && viewTakeButtonState == ViewTakeButtonState.STATE_READY) {
                    start();
                }
                break;
            case MotionEvent.ACTION_UP:
                //手指移出
                if (viewTakeButtonState == ViewTakeButtonState.STATE_TAKEING) {
                    stop();
                }
                break;
        }

        return true;
    }

最后,将事件回调给使用方去执行录制等动作(结合代码)

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;

public class VideoTakeButton extends View {
//    private String TAG = VideoTakeButton.class.getSimpleName();

    public VideoTakeButton(Context context) {
        this(context, null);
    }

    public VideoTakeButton(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public VideoTakeButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //获取配置的资源属性
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.VideoTakeButton);
        cBackColor = typedArray.getColor(R.styleable.VideoTakeButton_cBackColor, R.color.colorPrimary);
        oInColor = typedArray.getColor(R.styleable.VideoTakeButton_oInColor, R.color.colorPrimary);
        durTime = typedArray.getInt(R.styleable.VideoTakeButton_durTime, 10000);
        rangWidth = typedArray.getDimension(R.styleable.VideoTakeButton_rangWidth, 10);

        init();

    }

    private Paint cBtnPaint;//中间按钮的画笔
    private Paint oCPaint;//外环转动圆环的画笔

    private int cBackColor;//中间按钮的背景
    private int oInColor;//外环转动圆环的填充色
    private long durTime;//圆环转动一圈持续的时间
    private float rangWidth;//走动的圆环宽度
    private int rangAndCirPadding = 20;//默认按钮和走动圆环的 的距离
    ViewTakeButtonState viewTakeButtonState;

    OnVideoTakeButtonListener onVideoTakeButtonListener;
    float sweepAngle = 0f;

    private void init() {
        viewTakeButtonState = ViewTakeButtonState.STATE_READY;
        cBtnPaint = new Paint();
        cBtnPaint.setColor(cBackColor);
        cBtnPaint.setStyle(Paint.Style.FILL);
        cBtnPaint.setAntiAlias(true);

        oCPaint = new Paint();
        oCPaint.setColor(oInColor);
        oCPaint.setStrokeWidth(rangWidth);
        oCPaint.setStyle(Paint.Style.STROKE);
        oCPaint.setAntiAlias(true);
    }

    /**
     * 添加监听
     *
     * @param onVideoTakeButtonListener
     */
    public void addVideoTakeButtonListener(OnVideoTakeButtonListener onVideoTakeButtonListener) {
        this.onVideoTakeButtonListener = onVideoTakeButtonListener;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(measureDimension(widthMeasureSpec), measureDimension(heightMeasureSpec));
    }
    ValueAnimator valueAnimator;
    /**
     * 开始
     */
    private void start() {
         valueAnimator = ValueAnimator.ofFloat(360f);
        valueAnimator.setDuration(durTime);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {

                sweepAngle = (float) animation.getAnimatedValue();
                if (onVideoTakeButtonListener!=null&&sweepAngle==360) {
                    viewTakeButtonState = ViewTakeButtonState.STATE_READY;
                    onVideoTakeButtonListener.stop();
                }
                invalidate();
            }
        });
        valueAnimator.start();
    }
    private void stop() {
        if (valueAnimator!=null){
            valueAnimator.cancel();
        }
    }

    //重置
    public void reset(){
        sweepAngle=0;
        invalidate();
    }

    int measureDimension(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        switch (specMode) {
            case MeasureSpec.AT_MOST:
                result = 100;
                break;

            case MeasureSpec.UNSPECIFIED:
            case MeasureSpec.EXACTLY:
                result = specSize;
                break;

        }
        return result;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, Math.min(getWidth(), getHeight()) / 2 - rangWidth - rangAndCirPadding, cBtnPaint);
        canvas.drawArc(rangWidth / 2, rangWidth / 2, getWidth() - rangWidth / 2, getHeight() - rangWidth / 2, 270, sweepAngle, false, oCPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //手指按下
                if (isOnClickCnnter(event.getX(), event.getY()) && viewTakeButtonState == ViewTakeButtonState.STATE_READY) {
                    start();
                    viewTakeButtonState = ViewTakeButtonState.STATE_TAKEING;
                    if (onVideoTakeButtonListener!=null) {
                        onVideoTakeButtonListener.start();
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                //手指移除
                if (viewTakeButtonState == ViewTakeButtonState.STATE_TAKEING) {
                    stop();
                    viewTakeButtonState = ViewTakeButtonState.STATE_READY;
                    if (onVideoTakeButtonListener!=null) {
                        onVideoTakeButtonListener.stop();
                    }
                }
                break;
        }

        return true;
    }

    //是不是按在中心圆的 位置
    private boolean isOnClickCnnter(float x, float y) {
        return x > (rangWidth + rangAndCirPadding) && x < (getWidth() - rangWidth - rangAndCirPadding) && y > (rangWidth + rangAndCirPadding) && y < (getHeight() - rangWidth - rangAndCirPadding);
    }

    enum ViewTakeButtonState {
        STATE_READY,
        STATE_TAKEING
    }

  public   interface OnVideoTakeButtonListener {
        void start();
        void stop();
    }
}

上一篇下一篇

猜你喜欢

热点阅读