Android 仿微信拍攝按鈕

本身寫了一個另外版本,感受不是很好,借鑑了一下老哥的代碼,優化了一下,感謝老哥,尾部附連接。android

簡單粗暴,沒有太多擴展,若是須要能夠寫一些擴展,我只是實現出來懶得擴展了,由於就是本身寫着玩的,沒有什麼需求。git

話很少說,直接上代碼: `public class VideoTakeButton extends View {github

private static final String TAG = "VideoTakeButton";

/**
 * 外邊框半透明圓的畫筆
 */
private Paint mPaint0;

/**
 * 內部圓的畫筆
 */
private Paint mPaint1;

/**
 * 進度條的畫筆
 */
private Paint mPaint2;

/**
 * 進度條動畫
 */
private ValueAnimator mProgressAni;

/**
 * 最大拍攝時間,視頻只能拍這麼久
 */
private int mMaxTime = 15;

/**
 * 視頻的最小拍攝時間,小於這個時間都按拍照處理
 */
private float mMinTime = 0.6F;

/**
 * 外邊框的半透明圓的尺寸
 */
private float bigCircleRadius = 0;
/**
 * 外邊框半透明圓的動畫開始尺寸
 */
private float bigCircleStartRadius = 0;
/**
 * 外邊框半透明圓的動畫結束尺寸
 */
private float bigCircleEndRadius = 0;

/**
 * 內部圓的尺寸
 */
private float smallCircleRadius = 0;
/**
 * 內部圓的動畫開始尺寸
 */
private float smallCircleStartRadius = 0;
/**
 * 內部圓的動畫結束尺寸
 */
private float smallCircleEndRadius = 40;

/**
 * 拍攝視頻的進度條
 */
private float progress = 0;

/**
 * 開始點擊的消息碼
 */
private static final int START_CLICK = 0x001;
/**
 * 長按事件的消息碼
 */
private static final int LONG_CLICK = 0x002;

/**
 * 按鈕按下時間
 */
private long mStartTime = 0L;

/**
 * 按鈕擡起時間
 */
private long mEndTime = 0L;
/**
 * 長按最短期  單位毫秒
 */
public long LONG_CLICK_MIN_TIME = 800L;


public VideoTakeButton(Context context) {
    super(context);
    init(context);
}

public VideoTakeButton(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    init(context);
}

public VideoTakeButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context);
}

private void init(Context context) {
    mPaint0 = new Paint();
    mPaint0.setColor(Color.WHITE);
    mPaint0.setAlpha(150);

    mPaint1 = new Paint();
    mPaint1.setColor(Color.WHITE);
    mPaint1.setAlpha(255);

    mPaint2 = new Paint();
    mPaint2.setColor(Color.GREEN);
    mPaint2.setAlpha(255);

    //進度條的屬性動畫
    mProgressAni = ValueAnimator.ofFloat(0, 360f);
    mProgressAni.setDuration(mMaxTime * 1000);
}

private ViewHandler viewHandler = new ViewHandler(this);

static class ViewHandler extends android.os.Handler {

    private WeakReference<VideoTakeButton> weakReference = null;

    public ViewHandler(VideoTakeButton videoTakeButton) {
        weakReference = new WeakReference<>(videoTakeButton);
    }

    @Override
    public void handleMessage(@NonNull Message msg) {
        super.handleMessage(msg);
        if (weakReference == null || weakReference.get() == null) return;
        final VideoTakeButton videoTakeButton = weakReference.get();
        switch (msg.what) {
            case VideoTakeButton.START_CLICK:
                videoTakeButton.startAnimationClick();
                break;
            case VideoTakeButton.LONG_CLICK:
                if (videoTakeButton.callBack != null) {
                    videoTakeButton.callBack.takeVideoStart();
                }
                break;
        }
    }
}

@Override
public void draw(Canvas canvas) {
    super.draw(canvas);

    float x = getWidth();
    float y = getHeight();

    float pointX = x / 2;
    float pointY = y / 2;

    bigCircleStartRadius = x / 2 - x / 15;
    bigCircleEndRadius = x / 2;

    smallCircleStartRadius = x * 2 / 5 - x / 15;
    smallCircleEndRadius = (x * 2 / 5 - x / 15) / 2;
    if (isRecording) {
        canvas.drawCircle(pointX, pointY, bigCircleRadius, mPaint0);
        canvas.drawCircle(pointX, pointY, smallCircleRadius, mPaint1);
        //使用離屏繪製
        int layerID = canvas.saveLayer(0, 0, getWidth(), getHeight(), mPaint2, Canvas.ALL_SAVE_FLAG);
        canvas.drawArc(x / 15, x / 15, x - x / 15, x - x / 15, 270, progress, true, mPaint2);
        mPaint2.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
        canvas.drawArc(0, 0, x, x, 270, progress, true, mPaint2);
        mPaint2.setXfermode(null);
        canvas.restoreToCount(layerID);
    } else {
        bigCircleRadius = bigCircleStartRadius;
        canvas.drawCircle(pointX, pointY, bigCircleRadius, mPaint0);

        smallCircleRadius = smallCircleStartRadius;
        canvas.drawCircle(pointX, pointY, smallCircleRadius, mPaint1);
    }

}

private void startAnimationClick() {
    ValueAnimator smallCircle = ValueAnimator.ofFloat(smallCircleStartRadius, smallCircleEndRadius);
    smallCircle.setDuration(300);
    smallCircle.addUpdateListener(animation -> {
        smallCircleRadius = (float) animation.getAnimatedValue();
        invalidate();
    });
    ValueAnimator bigCircle = ValueAnimator.ofFloat(bigCircleStartRadius, bigCircleEndRadius);
    bigCircle.setDuration(300);
    bigCircle.addUpdateListener(animation -> {
        if (isRecording) {
            bigCircleRadius = (float) animation.getAnimatedValue();
            invalidate();
        }
    });
    smallCircle.start();
    bigCircle.start();
    smallCircle.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animator) {

        }

        @Override
        public void onAnimationEnd(Animator animator) {
            //開始繪製圓形進度條
            if (isRecording) {
                startAniProgress();
            }
        }

        @Override
        public void onAnimationCancel(Animator animator) {

        }

        @Override
        public void onAnimationRepeat(Animator animator) {

        }
    });
}

private void startAniProgress() {
    if (mProgressAni == null) return;
    mProgressAni.start();
    mProgressAni.addUpdateListener(valueAnimator -> {
        progress = (float) valueAnimator.getAnimatedValue();
        postInvalidate();
    });
    mProgressAni.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            isRecording = false;
            progress = 0;
            postInvalidate();
        }
    });
}

private boolean isRecording = false;

@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
    super.onTouchEvent(event);
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            isRecording = true;
            mStartTime = System.currentTimeMillis();
            viewHandler.sendEmptyMessage(START_CLICK);
            viewHandler.sendEmptyMessageDelayed(LONG_CLICK, LONG_CLICK_MIN_TIME);
            break;
        case MotionEvent.ACTION_MOVE:
            break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            isRecording = false;
            mEndTime = System.currentTimeMillis();
            if (mEndTime - mStartTime < LONG_CLICK_MIN_TIME) {
                if (viewHandler.hasMessages(LONG_CLICK)) {
                    viewHandler.removeMessages(LONG_CLICK);
                }
                if (callBack != null) {
                    callBack.takePhoto();
                }
            } else {
                if (mProgressAni != null && progress / 10 < mMinTime) {
                    if (callBack != null) {
                        callBack.takePhoto();
                    }
                } else {
                    if (callBack != null) {
                        callBack.takeVideoEnd();
                    }
                }
            }
            if (mProgressAni != null) {
                mProgressAni.cancel();
            }
            break;
    }
    return true;
}

interface CallBack {

    void takePhoto();

    void takeVideoStart();

    void takeVideoEnd();

}

private CallBack callBack;

public void setCallBack(CallBack callBack) {
    this.callBack = callBack;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int screenWidth = getScreenWidth();
    int width = screenWidth * 23 / 100;
    setMeasuredDimension(width, width);
}

/**
 * 獲取屏幕寬度
 *
 * @return
 */
private int getScreenWidth() {
    WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
    DisplayMetrics displayMetrics = new DisplayMetrics();
    windowManager.getDefaultDisplay().getMetrics(displayMetrics);
    return displayMetrics.widthPixels;
}
複製代碼

}`canvas

感謝老哥:🙏🙏🙏 Android 自定義View 仿微信錄製 長按錄製 點擊拍照微信

相關文章
相關標籤/搜索