前言
项目中有个类似微信拍小视频上传的功能,所以设计那边就做了一套拍摄用的UI图,其中录制按钮类似微信那个,但又有点不同。先上效果看一下。
这里说明一下,GIF图刚开始是停顿2秒,是因为我录制的时候自己操作的问题,才会出现的延迟,真正跑起来时是不会有卡顿效果的。
因为这个效果系统控件是没有的,所以只能自己自定义View来实现了。
下面说一下我的思路,
① 需要画个正常的圆
② 需要画个按压后变大的圆(半径变大)
③ 在圆变大时需要在圆的外部画圆形进度条
我们先解决第一个问题:
canvas.drawCircle(mWidth / 2, mHeight / 2, mRadius, mBgPaint);
这就画了一个中规中矩的圆了。。。
第二问题:
canvas.drawCircle(mWidth / 2, mHeight / 2, (float) (mRadius*1.2), mBgPaint);
这里我们将半径变为了之前的1.2倍了,所以当我们点击的时候半径会变大。点击的时候变大这里我是覆写了onTouchEvent来处理的,稍后我们一起来看一下代码。
最后一个问题:
这里我们直接画进度条肯定是不好画的,但是我们换个思路就比较容易理解了,画圆弧。画圆弧有2中画法,一种是空心的,一种实心的。
第一种:
canvas.drawArc(mRectF, -90, 90, false, mRecordPaint);
效果图:
第二种:
canvas.drawArc(mRectF, 90, 240, true, mRecordPaint);
效果图:
这里我们使用第一种空心圆弧,这样就可以模仿圆形外部进度条效果了。
下面给出自定义View的全部代码:
public class CircleProgressBar extends View {
// 录制时的环形进度条
private Paint mRecordPaint;
// 录制时点击的圆形按钮
private Paint mBgPaint;
// 画笔宽度
private int mStrokeWidth;
// 圆形按钮半径
private int mRadius;
//控件宽度
private int mWidth;
//控件高度
private int mHeight;
// 圆的外接圆
private RectF mRectF;
//progress max value
private int mMaxValue=100;
//per progress value
private int mProgressValue;
//是否开始record
private boolean mIsStartRecord=false;
//Arc left、top value
private int mArcValue;
//录制 time
private long mRecordTime;
private Handler mHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
++mProgressValue;
postInvalidate();
//当没有达到最大值时一直绘制
if (mProgressValue <= mMaxValue) {
mHandler.sendEmptyMessageDelayed(0, 100);
}
}
};
public CircleProgressBar(Context context) {
this(context, null);
}
public CircleProgressBar(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initParams(context);
}
//初始化画笔操作
private void initParams(Context context){
mArcValue=mStrokeWidth = Px2DpUtil.dp2px(context, 3);
mBgPaint = new Paint();
mBgPaint.setAntiAlias(true);
mBgPaint.setColor(context.getResources().getColor(R.color.white));
mBgPaint.setStrokeWidth(mStrokeWidth);
mBgPaint.setStyle(Paint.Style.FILL);
mRecordPaint = new Paint();
mRecordPaint.setAntiAlias(true);
mRecordPaint.setColor(context.getResources().getColor(R.color.c_3ec88e));
mRecordPaint.setStrokeWidth(mStrokeWidth);
mRecordPaint.setStyle(Paint.Style.STROKE);
mRadius = Px2DpUtil.dp2px(context, 30);
mRectF = new RectF();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mWidth=getWidth();
mHeight=getHeight();
if (mWidth != mHeight) {
int min = Math.min(mWidth, mHeight);
mWidth=min;
mHeight=min;
}
if (mIsStartRecord) {
canvas.drawCircle(mWidth / 2, mHeight / 2, (float) (mRadius*1.2), mBgPaint);
if(mProgressValue<=mMaxValue) {
//left--->距Y轴的距离
//top--->距X轴的距离
//right--->距Y轴的距离
//bottom--->距X轴的距离
mRectF.left = mArcValue;
mRectF.top = mArcValue;
mRectF.right = mWidth - mArcValue;
mRectF.bottom = mHeight - mArcValue;
canvas.drawArc(mRectF, -90, ((float)mProgressValue / mMaxValue) * 360, false, mRecordPaint);
if (mProgressValue == mMaxValue) {
mProgressValue = 0;
mHandler.removeMessages(0);
mIsStartRecord = false;
//这里可以回调出去表示已到录制时间最大值
//code.....
}
}
}else{
canvas.drawCircle(mWidth / 2, mHeight / 2, mRadius, mBgPaint);
}
}
//重新该方法来完成触摸时,圆变大的效果
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mIsStartRecord=true;
mRecordTime=System.currentTimeMillis();
mHandler.sendEmptyMessage(0);
//这里可以回调出去表示已经开始录制了
//code.....
break;
case MotionEvent.ACTION_UP:
if (mRecordTime > 0) {
//录制的时间(单位:秒)
int actualRecordTime= (int) ((System.currentTimeMillis()-mRecordTime)/1000);
//这里回调出去表示已经取消录制了
//code.....
}
mHandler.removeMessages(0);
mIsStartRecord=false;
mRecordTime=0;
mProgressValue=0;
postInvalidate();
break;
case MotionEvent.ACTION_CANCEL:
//这里可以回调出去表示已经取消录制了
//code.....
mHandler.removeMessages(0);
mIsStartRecord=false;
mRecordTime=0;
mProgressValue=0;
postInvalidate();
break;
}
return true;
}
}
好了,具体思路和实现都在这里了。有什么问题可以评论问我。
快乐生活!快乐工作!快乐编程!