美文网首页
Android自定义View(短视频录制按钮)

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

作者: 火星移民局局长 | 来源:发表于2020-09-14 15:31 被阅读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);
    //圆的半径=控件布局-圆环的宽度-与圆环的边距
         
    
    • 圆环:因为是有动画效果,所以sweepAngle参数需要动态修改
    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();
        }
    }
    
    

    相关文章

      网友评论

          本文标题:Android自定义View(短视频录制按钮)

          本文链接:https://www.haomeiwen.com/subject/wbjzektx.html