本身写了一个另外版本,感受不是很好,借鉴了一下老哥的代码,优化了一下,感谢老哥,尾部附连接。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 仿微信录制 长按录制 点击拍照微信