本身寫了一個另外版本,感受不是很好,借鑑了一下老哥的代碼,優化了一下,感謝老哥,尾部附連接。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 仿微信錄製 長按錄製 點擊拍照微信