Android录制按钮源码解析

作者:碧云天丶 时间:2022-06-24 19:24:44 

本文实例为大家分享了Android实现录制按钮的具体代码,供大家参考,具体内容如下

初始化

布局文件中参数


private void initParame(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
   TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RButtonY, defStyleAttr, 0);
   //外圆和内部正方形之间的间距
   mCircleOutMarginSize = typedArray.getDimensionPixelSize(R.styleable.RButtonY_rby_circle_out_margin, 5);
   //外圆画笔的宽度
   mCircleWidth = typedArray.getDimensionPixelSize(R.styleable.RButtonY_rby_circle_width, 5);
   //外圆画笔的颜色
   mCirclePaintColor = typedArray.getColor(R.styleable.RButtonY_rby_circle_paint_color, Color.YELLOW);
   //内部正方形画笔的颜色
   mRectPaintColor = typedArray.getColor(R.styleable.RButtonY_rby_rect_paint_color, Color.RED);
   //内部正方形初始边长相对于外圆内切正方形边长比率 0-1
   mRectRateStart = typedArray.getFloat(R.styleable.RButtonY_rby_rect_rate_start, 0.9f);
   //内部正方形结束边长相对于外圆内切正方形边长比率 0-1
   mRectRateFinish = typedArray.getFloat(R.styleable.RButtonY_rby_rect_rate_fnish, 0.5f);
   //录制规定最短时间
   mShortest = typedArray.getInteger(R.styleable.RButtonY_rby_short_time, 3);
   //录制规定最长时间
   mLongest = typedArray.getInteger(R.styleable.RButtonY_rby_long_time, 10);
   typedArray.recycle();
}

画笔初始化


// Paint.Style.FILL设置只绘制图形内容
// Paint.Style.STROKE设置只绘制图形的边
// Paint.Style.FILL_AND_STROKE设置都绘制
private void initPaint() {
   //外圆画笔
   mCirclePaint = new Paint();
   mCirclePaint.setAntiAlias(true);
   mCirclePaint.setColor(mCirclePaintColor);
   mCirclePaint.setStyle(Paint.Style.STROKE);
   mCirclePaint.setStrokeWidth(mCircleWidth);
   //内部正方形画笔
   mRectPaint = new Paint();
   mRectPaint.setAntiAlias(true);
   mRectPaint.setColor(mRectPaintColor);
   mRectPaint.setStyle(Paint.Style.FILL_AND_STROKE);
}

内部正方形RectF初始化


private void initRect() {
       mRectF = new RectF();
}

内部正方形所需动画初始化, 当开始录制或者结束录制时候,内部正方形会有一个动画效果,这个动画效果需要内部正方形边长改变才能实现.


/**
* 初始化动画
* 这里对动画进行监听, 获取正方形边长随动画改变的值,然后重绘
*/
private void initAnimator() {
   mAnimator = new ValueAnimator();
   /**
    * onAnimationStart() - 当动画开始的时候调用.
    * onAnimationEnd() - 动画结束时调用.
    * onAnimationRepeat() - 动画重复时调用.
    * onAnimationCancel() - 动画取消时调用.取消动画也会调用onAnimationEnd,它不会关系动画是怎么结束的。
    */
   mAnimator.addListener(new AnimatorListenerAdapter() {
       @Override
       public void onAnimationEnd(Animator animation) {
           //动画结束
           isAnimRuning = false;
       }
       @Override
       public void onAnimationStart(Animator animation) {
           //动画开始
           isAnimRuning = true;
       }
   });
   //动画进度监听,获取正方形随动画变化的边长,然后重绘
   mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
       @Override
       public void onAnimationUpdate(ValueAnimator animation) {
           //动态获取正方形边长
           mTempRectSize = (float) animation.getAnimatedValue();
           invalidate();//重绘
       }
   });
}

确定圆形半径,圆心坐标,内部正方形边长等


@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    int width = getWidth();
    int height = getHeight();
    //圆心坐标
    centerX = width / 2;
    centerY = height / 2;
    //半径
    radius = Math.min(centerX, centerY) - mCircleOutMarginSize / 2;
    //pow 平方,sqrt 开方
    //正方形开始边长,圆形直径的平方除以二再开放,为正方形边长.
    mRectStartSize = (int) (Math.sqrt(Math.pow(radius * 2, 2) / 2) * mRectRateStart);
    //正方形结束边长
    mRectEndSize = (int) (mRectStartSize * mRectRateFinish);
   //mTempRectSize == 0 时, 即第一创建该View.
   if (mTempRectSize == 0) {
       //如果屏幕旋转,onLayout将被回调,此时并不希望mTempRectSize被重新赋值为mRectStartSize(开始状态).
       //所以只有当第一次创建时,才需要为mTempRectSize赋值为mRectStartSize(开始状态)
       mTempRectSize = mRectStartSize;
   }
}

绘制内部正方形和外圆


@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //外圆绘制
    canvas.drawCircle(centerX, centerY, radius, mCirclePaint);
    //正方形四点坐标
    int mLeftRectTemp = (int) (centerX - mTempRectSize / 2);
    int mRightRectTemp = (int) (centerX + mTempRectSize / 2);
    int mTopRectTemp = (int) (centerY + mTempRectSize / 2);
    int mButtonRectTemp = (int) (centerY - mTempRectSize / 2);
    //绘制正方形
    mRectF.set(mLeftRectTemp, mTopRectTemp, mRightRectTemp, mButtonRectTemp);
    //(float) Math.sqrt(radius): 圆角半径
    canvas.drawRoundRect(mRectF, (float) Math.sqrt(radius), (float) Math.sqrt(radius), mRectPaint);
}

录制开始和结束方法以及动画执行方法


/**
* 录制开始
*/
private void recordStart() {
   //正方形开始动画
   startAnimation(mRectStartSize, mRectEndSize);
   if (rbyCb != null) {
       //录制开始的回调
       rbyCb.startCb(String.valueOf(mCurrent));
   }
   //开始计时
   mHandler.sendEmptyMessage(0);
   //录制标识为开始
   up = true;
   mTempRectSize = mRectEndSize;
}
/**
* 录制结束
*/
private void recordFinish() {
   //正方形结束动画
   startAnimation(mRectEndSize, mRectStartSize);
   if (rbyCb != null) {
       //结束时回调
       rbyCb.finishCb(String.valueOf(mCurrent));
   }
   //录制结束,当前时间归0
   mCurrent = 0;
   mHandler.removeCallbacksAndMessages(null);
   //录制标识为结束
   up = false;
   mTempRectSize = mRectStartSize;
}
/**
* 开始动画
*
* @param startValue
* @param endValue
*/
private void startAnimation(float startValue, float endValue)
   mAnimator.setFloatValues(startValue, endValue);
   mAnimator.setDuration(100);
   mAnimator.setInterpolator(new LinearInterpolator());
   mAnimator.start();
}

回调接口


public interface RBYCallback {
   /**
    * 记录结束的回调
    *
    * @param current
    */
   void finishCb(String current);
   /**
    * 每一秒 都会触发该回调
    *
    * @param current
    */
   void eventCb(String current);
   /**
    * 开始记录的回调
    */
   void startCb(String current);
   /**
    * 录制时长小于录制最短要求时间之时,用户点击按钮时候,回调该方法
    */
   void lessShortTimeRecode(String current);
}

对控件点击事件进行处理


@Override
public boolean onTouchEvent(MotionEvent event) {
   switch (event.getAction()) {
       case MotionEvent.ACTION_UP:
           //如果正方形动画正在播放,就拒绝按钮点击
           if (isAnimRuning) return true;
           //up为false代表未开始记录,true 代表开始记录
           //未开始记录时,mCurrent是等于0
           if (!up && mCurrent == 0) {
               recordStart();
           }
           //已开始记录,并且当前录制时间大于或者等于所设置的最短记录时长,则按钮可以手动结束
           if (up && mCurrent >= mShortest) {
               recordFinish();
           }
           //已开始记录,当前录制时间小于所设置的最短记录时长,并且录制时间大于1,则回调方法通知当前还不能手动结束录制
           if (up && mCurrent < mShortest && mCurrent >= 1) {
               if (rbyCb != null) {
                   rbyCb.lessShortTimeRecode(String.valueOf(mCurrent));
               }
           }
           break;
   }
   return true;//消费事件
}

屏幕旋转保存与还原数据


//屏幕旋转时候保存必要的数据
@Nullable
@Override
protected Parcelable onSaveInstanceState() {
   if (mCurrent != 0) {
       Bundle bundle = new Bundle();
       //保存系统其他原有的状态信息
       bundle.putParcelable("instance", super.onSaveInstanceState());
       //保存当前的一些状态
       bundle.putFloat("rect_size", mTempRectSize);//保存方形边长
       bundle.putBoolean("up", up);//当前录制状态
       bundle.putInt("mCurrent", mCurrent);//当前录制时间
       return bundle;
   } else {
       return super.onSaveInstanceState();
   }
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
   //判断state的类型是否为bundle,若是则从bundle中取数据
   if (state instanceof Bundle) {
       Bundle bundle = (Bundle) state;
       mTempRectSize = bundle.getFloat("rect_size");
       up = bundle.getBoolean("up");
       mCurrent = bundle.getInt("mCurrent");
       //开始计时
       mHandler.sendEmptyMessage(0);
       super.onRestoreInstanceState(bundle.getParcelable("instance"));
       return;
   }
   super.onRestoreInstanceState(state);
}

定时mHandler


@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
   @Override
   public void handleMessage(@NonNull Message msg) {
       super.handleMessage(msg);
       mCurrent++;
       if (rbyCb != null) {
           rbyCb.eventCb(String.valueOf(mCurrent));
       }
       if (mCurrent >= mLongest) {//当前记录时间大于或等于最大记录时间,将自动结束记录
           recordFinish();
       } else {
           mHandler.sendEmptyMessageDelayed(0, 1000);
       }
   }
};

页面销毁处理


//页面销毁,清空消息,防止内存泄漏
@Override
protected void onDetachedFromWindow() {
   super.onDetachedFromWindow();
   mHandler.removeCallbacksAndMessages(null);
   mHandler = null;
}

效果图

Android录制按钮源码解析

来源:https://blog.csdn.net/MoLiao2046/article/details/104688172

标签:Android,录制,按钮
0
投稿

猜你喜欢

  • Android实现保存QQ账号与密码功能(文件存储)

    2023-07-04 22:26:31
  • JDK源码之Vector与HashSet解析

    2021-09-06 10:47:23
  • java通过Jsoup爬取网页过程详解

    2021-12-20 03:24:10
  • Android内容提供者ContentProvider用法实例分析

    2021-06-25 09:33:04
  • springboot schedule 解决定时任务不执行的问题

    2021-05-30 05:00:38
  • c#同步两个子目录文件示例分享 两个文件夹同步

    2022-01-25 05:03:03
  • MyBatis-Plus 如何单元测试的实现

    2022-03-02 19:45:08
  • Android Button按钮点击背景和文字变化操作

    2023-10-27 22:27:22
  • 浅谈Java8 判空新写法

    2023-06-21 15:55:08
  • Java中ArrayList和LinkedList的遍历与性能分析

    2023-10-31 11:04:17
  • Android编程中context及全局变量实例详解

    2023-11-17 05:58:40
  • C# 线程安全详解

    2023-02-07 10:40:46
  • SpringBoot2 实现JPA分页和排序分页的案例

    2022-02-23 13:26:08
  • JavaWeb开发使用Cookie创建-获取-持久化、自动登录、购物记录、作用路径

    2022-01-11 10:37:28
  • Springboot如何利用拦截器拦截请求信息收集到日志详解

    2023-03-09 02:30:57
  • Java之单例模式实现方案详解

    2022-02-15 19:02:29
  • Java实现添加文字水印&图片水印的方法详解

    2023-01-28 08:11:39
  • Android WebView使用的技巧与一些坑

    2022-10-18 12:57:23
  • C# 基础入门--关键字

    2023-01-22 15:44:23
  • Java实现一个简单的定时器代码解析

    2021-11-24 20:25:38
  • asp之家 软件编程 m.aspxhome.com