自定義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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章