Android – 仿微信拍摄视频按钮

前言

项目中有个类似微信拍小视频上传的功能,所以设计那边就做了一套拍摄用的UI图,其中录制按钮类似微信那个,但又有点不同。先上效果看一下。

这里说明一下,GIF图刚开始是停顿2秒,是因为我录制的时候自己操作的问题,才会出现的延迟,真正跑起来时是不会有卡顿效果的。

点击录制按钮效果.gif

因为这个效果系统控件是没有的,所以只能自己自定义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);

效果图:

空心圆弧-图片来源于网络.png

第二种:

canvas.drawArc(mRectF, 90, 240, true, mRecordPaint);

效果图:

实心圆弧-图片来源于网络.png

这里我们使用第一种空心圆弧,这样就可以模仿圆形外部进度条效果了。

下面给出自定义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;
    }
}

好了,具体思路和实现都在这里了。有什么问题可以评论问我。

快乐生活!快乐工作!快乐编程!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏何俊林

一个酷炫的音乐播放界面

前言:网易云音乐是一款非常优秀的音乐播放器,尤其是播放界面,使用唱盘机风格,显得格外古典优雅。本文是AchillesL出于学习与挑战的想法,思考播放界面背后的实...

1.3K6
来自专栏郭霖

Android高级图片滚动控件,编写3D版的图片轮播器

大家好,好久不见了,最近由于工作特别繁忙,已经有一个多月的时间没写博客了,我也是深感惭愧。那么今天的这篇既然是阔别了一个多月的文章,当然要带来更加给力点的内容了...

7678
来自专栏向治洪

Android仿网易云音乐播放界面

概述 网易云音乐是一款非常优秀的音乐播放器,尤其是播放界面,使用唱盘机风格,显得格外古典优雅。这里抛砖引玉,原文地址:http://www.jianshu.co...

94210
来自专栏24K纯开源

用Qt写软件系列五:一个安全防护软件的制作(1)

引言       又有许久没有更新了。Qt,我心爱的Qt,为了找工作不得不抛弃一段时间,业余时间来学一学了。本来计划要写一系列关于Qt组件美化的博文,但是写了几...

2137
来自专栏数据小魔方

数据地图系列10|excel(VBA)数据地图透明度填充法

今天要跟大家分享数据地图系列的第10篇——excel(VBA)数据地图透明度填充法。 这种方法的制作步骤难度与前一篇相比都较低,但是涉及到的VBA代码却要比前一...

6415
来自专栏向治洪

深入理解Android渲染机制

基础知识 CPU: 中央处理器,它集成了运算,缓冲,控制等单元,包括绘图功能.CPU将对象处理为多维图形,纹理(Bitmaps、Drawables等都是一起打包...

2236
来自专栏Python小屋

Python操作高版本Excel文件:颜色、边框、合并单元格

本文主要颜色Python扩展库openpyxl的一些基本用法,包括创建工作簿、选择活动工作表、写入单元格数据,设置单元格字体颜色、边框样式,合并单元格等等。 f...

4785
来自专栏偏前端工程师的驿站

CSS魔法堂:再次认识font

一、前言                                 文字承载着站点内涵,而良好的字体、排版则为用户提供舒适的阅读体验。本文打算对字体稍微深...

25910
来自专栏Android 开发学习

NestedScrollView 嵌套 ListView 实现滑动折叠效果

5185
来自专栏青玉伏案

iOS开发之画图板(贝塞尔曲线)

  贝塞尔曲线,听着挺牛气一词,不过下面我们在做画图板的时候就用到贝塞尔绘直线,没用到绘制曲线的功能。如果会点PS的小伙伴会对贝塞尔曲线有更直观的理解。这篇博文...

23810

扫码关注云+社区