diff --git a/README.md b/README.md
index 6857610..224d5ee 100644
--- a/README.md
+++ b/README.md
@@ -192,7 +192,60 @@ cameraHolder = CameraHolder(
.setMinFaceSize(0.6f)//人脸最小占图片的百分比
```
-
+ # cameraButtom
+
+此按钮控件用于拍照和录像,支持点击拍照,点击录像和长按录像,长按录制有动画
+
+支持设置录制时长,到达录制时长后回调通知结束录制。
+
+可以设置按钮仅支持拍照,仅支持录制,或都支持
+
+1. 在开启长按录制时,点击录制将不可用
+
+2. 开启点击录制时,拍照不可用
+
+布局文件示例
+
+```
+
+```
+
+使用示例
+
+```
+page.fullCaptureBtn.setCaptureListener(object : DefaultCaptureListener(){
+ //拍照
+ override fun takePictures() {
+ cameraXFragment.takePhoto()
+ }
+ //开始录制视频
+ override fun recordStart() {
+ page.captureVideoBtn.visibility = View.GONE
+ LogUtils.dTag("录制activity", "开始")
+ cameraXFragment.takeVideo()
+ //录制视频时隐藏摄像头切换
+ page.switchBtn.visibility=View.GONE
+ }
+
+ //录制视频到达预定的时长,可以结束了
+ override fun recordShouldEnd(time: Long) {
+ page.captureVideoBtn.visibility = View.VISIBLE
+ LogUtils.dTag("录制activity", "停止")
+ cameraXFragment.stopTakeVideo(time)
+ page.switchBtn.visibility=View.VISIBLE
+ }
+})
+```
# 示例代码在app目录下。
diff --git a/camerax_lib/src/main/AndroidManifest.xml b/camerax_lib/src/main/AndroidManifest.xml
index d300f1e..6e2a752 100644
--- a/camerax_lib/src/main/AndroidManifest.xml
+++ b/camerax_lib/src/main/AndroidManifest.xml
@@ -11,8 +11,6 @@
-
-
\ No newline at end of file
diff --git a/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/buttons/CameraButton.kt b/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/buttons/CameraButton.kt
new file mode 100644
index 0000000..818dd9c
--- /dev/null
+++ b/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/buttons/CameraButton.kt
@@ -0,0 +1,375 @@
+package com.kiylx.camerax_lib.main.buttons
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.AnimatorSet
+import android.animation.ValueAnimator
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.RectF
+import android.os.CountDownTimer
+import android.util.AttributeSet
+import android.view.MotionEvent
+import android.view.View
+import com.kiylx.camerax_lib.R
+
+class CameraButton @JvmOverloads constructor(
+ context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
+) : View(context, attrs, defStyleAttr) {
+
+ private var longPassRecord = false//是否使用长按录制
+ private var state = STATE_IDLE //当前按钮触摸事件
+ private var buttonEvent = EVENT_IDLE//录制或拍照等事件
+ var buttonMode = BUTTON_STATE_ONLY_CAPTURE // 当前按钮支持的模式
+
+ private val progress_color = -0x11e951ea //进度条颜色
+ private val outside_color = -0x11232324 //外圆背景色
+ private val inside_color = -0x1 //内圆背景色
+ private val inside_record_color = -0xe8bc //内圆录制时背景色
+
+
+ private var event_Y = 0f//Touch_Event_Down时候记录的Y值
+ private val mPaint: Paint by lazy {
+ Paint()
+ }
+ private var strokeWidth = 0f//进度条宽度
+ private var outside_add_size = 0//长按外圆半径变大的Size
+ private var inside_reduce_size = 0//长安内圆缩小的Size
+
+ //中心坐标
+ private var center_X = 0f
+ private var center_Y = 0f
+
+ private var button_radius = 0f//按钮半径
+ private var button_outside_radius = 0f//外圆半径
+ private var button_inside_radius = 0f//内圆半径
+ private var button_size = 80 //按钮大小
+ private lateinit var rectF: RectF
+
+ private var progress = 0f//录制视频的进度
+ private var duration: Long = 60 * 1000 //录制视频最大时间长度,毫秒
+ private var recorded_time = 0//记录当前录制的时间
+
+ private var longPressRunnable
+ : LongPressRunnable = LongPressRunnable()//长按后处理的逻辑Runnable
+ private var captureListener
+ : CaptureListener? = null//按钮回调接口
+ private lateinit var timer
+ : RecordCountDownTimer //计时器
+
+ init {
+ initView(context, attrs)
+ }
+
+ /**
+ * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
+ */
+ private fun dip2px(context: Context, dpValue: Float): Int {
+ val scale = context.resources.displayMetrics.density
+ return (dpValue * scale + 0.5f).toInt()
+ }
+
+ /**
+ * 总要支持一下XML 中布局吧
+ *
+ * @param context CONTEXT
+ * @param attrs ATTRS
+ */
+ fun initView(context: Context, attrs: AttributeSet?) {
+ val arr = getContext().obtainStyledAttributes(attrs, R.styleable.CameraButton)
+ button_size =
+ dip2px(context, arr.getInteger(R.styleable.CameraButton_size, button_size).toFloat())
+ val tmp = arr.getInteger(R.styleable.CameraButton_maxDuration, 60)
+ if (tmp > 1) {
+ duration = tmp * 1000L
+ }
+
+ buttonMode = arr.getInteger(R.styleable.CameraButton_buttonMode, BUTTON_STATE_ONLY_CAPTURE)
+ longPassRecord=arr.getBoolean(R.styleable.CameraButton_longPassRecord,false)
+
+ button_radius = button_size / 2.0f
+ button_outside_radius = button_radius
+ button_inside_radius = button_radius * 0.85f
+ strokeWidth = (button_size / 15).toFloat()
+ outside_add_size = button_size / 8
+ inside_reduce_size = button_size / 8
+ mPaint.isAntiAlias = true
+
+ center_X = ((button_size + outside_add_size * 2) / 2).toFloat()
+ center_Y = ((button_size + outside_add_size * 2) / 2).toFloat()
+ rectF = RectF(
+ center_X - (button_radius + outside_add_size - strokeWidth / 2),
+ center_Y - (button_radius + outside_add_size - strokeWidth / 2),
+ center_X + (button_radius + outside_add_size - strokeWidth / 2),
+ center_Y + (button_radius + outside_add_size - strokeWidth / 2)
+ )
+ timer = RecordCountDownTimer(duration, duration / 360) //录制定时器
+ arr.recycle()
+ }
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+ setMeasuredDimension(button_size + outside_add_size * 2, button_size + outside_add_size * 2)
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ mPaint.style = Paint.Style.FILL
+ mPaint.color = outside_color //外圆(半透明灰色)
+ canvas.drawCircle(center_X, center_Y, button_outside_radius, mPaint)
+ mPaint.color = inside_color //内圆(白色)
+ canvas.drawCircle(center_X, center_Y, button_inside_radius, mPaint)
+
+ //如果状态为录制状态,则绘制录制进度条
+ if (buttonEvent == EVENT_RECORDERING) {
+ if (longPassRecord) {
+ mPaint.color = progress_color
+ mPaint.style = Paint.Style.STROKE
+ mPaint.strokeWidth = strokeWidth
+ canvas.drawArc(rectF, -90f, progress, false, mPaint)
+ } else {
+ mPaint.setColor(inside_record_color); //内圆(红色)
+ canvas.drawCircle(center_X, center_Y, button_inside_radius, mPaint);
+ }
+ }
+
+ }
+
+ override fun onTouchEvent(event: MotionEvent): Boolean {
+ when (event.action) {
+ MotionEvent.ACTION_DOWN -> {
+ if (event.pointerCount > 1 || buttonEvent == EVENT_CAPTURE) {
+ return false
+ }
+ event_Y = event.y //记录Y值
+ state = STATE_PRESS //修改当前状态为点击按下
+
+ //判断按钮状态是否为可录制状态
+ if ((buttonMode == BUTTON_STATE_ONLY_RECORDER || buttonMode == BUTTON_STATE_BOTH) && longPassRecord) {
+ postDelayed(
+ longPressRunnable,
+ 500
+ ) //同时延长500启动长按后处理的逻辑Runnable
+ }
+ }
+ MotionEvent.ACTION_MOVE -> {
+ if (captureListener != null && buttonEvent == EVENT_RECORDERING
+ && (buttonMode == BUTTON_STATE_ONLY_RECORDER || buttonMode == BUTTON_STATE_BOTH)
+ ) {
+ //记录当前Y值与按下时候Y值的差值,调用缩放回调接口
+ captureListener!!.recordZoom(event_Y - event.y)
+ }
+ }
+ MotionEvent.ACTION_UP -> {
+ //根据当前按钮的状态进行相应的处理
+ handlerPressByState()
+ state = STATE_IDLE
+ }
+ }
+ return true
+ }
+
+ //当手指松开按钮时候处理的逻辑
+ private fun handlerPressByState() {
+ removeCallbacks(longPressRunnable) //移除长按逻辑的Runnable
+ if (state == STATE_PRESS) {
+ if (captureListener != null) {
+ when (buttonMode) {
+ BUTTON_STATE_ONLY_RECORDER -> {
+ if (buttonEvent == EVENT_RECORDERING) {
+ timer.cancel() //停止计时器
+ recordEnd() //录制结束
+ } else {
+ //录视频
+ postDelayed(longPressRunnable, 500); //同时延长500启动长按后处理的逻辑Runnable
+ }
+ }
+ BUTTON_STATE_ONLY_CAPTURE ,BUTTON_STATE_BOTH -> {
+ startCaptureAnimation(button_inside_radius)
+ }
+ }
+ }
+ } else if (state== STATE_LONG_PRESS){
+ if (buttonEvent == EVENT_RECORDERING) {
+ timer.cancel() //停止计时器
+ recordEnd() //录制结束
+ }
+ }
+ }
+
+ //录制结束
+ fun recordEnd() {
+ if (captureListener != null) {
+ captureListener!!.recordShouldEnd(recorded_time.toLong()) //回调录制结束
+ }
+ resetRecordAnim() //重制按钮状态
+ }
+
+ //重制状态
+ private fun resetRecordAnim() {
+ state = STATE_IDLE
+ buttonEvent = EVENT_IDLE
+ progress = 0f //重制进度
+ invalidate()
+ //还原按钮初始状态动画
+ startRecordAnimation(
+ button_outside_radius,
+ button_radius,
+ button_inside_radius,
+ button_radius * 0.75f
+ )
+ }
+
+ //内圆动画
+ private fun startCaptureAnimation(inside_start: Float) {
+ val inside_anim = ValueAnimator.ofFloat(inside_start, inside_start * 0.75f, inside_start)
+ inside_anim.addUpdateListener { animation: ValueAnimator ->
+ button_inside_radius = animation.animatedValue as Float
+ invalidate()
+ }
+ inside_anim.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ super.onAnimationEnd(animation)
+ buttonEvent = EVENT_IDLE
+ }
+
+ override fun onAnimationStart(animation: Animator) {
+ super.onAnimationStart(animation)
+ if (captureListener != null) {
+ captureListener!!.takePictures()
+ }
+ state = STATE_IDLE
+ buttonEvent = EVENT_CAPTURE
+ }
+ })
+ inside_anim.duration = 50
+ inside_anim.start()
+ }
+
+ //内外圆动画
+ private fun startRecordAnimation(
+ outside_start: Float,
+ outside_end: Float,
+ inside_start: Float,
+ inside_end: Float
+ ) {
+ val outside_anim = ValueAnimator.ofFloat(outside_start, outside_end)
+ val inside_anim = ValueAnimator.ofFloat(inside_start, inside_end)
+ //外圆动画监听
+ outside_anim.addUpdateListener { animation: ValueAnimator ->
+ button_outside_radius = animation.animatedValue as Float
+ invalidate()
+ }
+ //内圆动画监听
+ inside_anim.addUpdateListener { animation: ValueAnimator ->
+ button_inside_radius = animation.animatedValue as Float
+ invalidate()
+ }
+ val set = AnimatorSet()
+ //当动画结束后启动录像Runnable并且回调录像开始接口
+ set.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ super.onAnimationEnd(animation)
+ //设置为录制状态
+ if (state == STATE_LONG_PRESS) {
+ captureListener?.recordStart()
+ buttonEvent = EVENT_RECORDERING
+ timer.start()
+ } else {
+ // 此处动画包括长按起始动画和还原动画 若不是长按状态应该还原状态为空闲????---CodeReview
+ state = STATE_IDLE
+ }
+ }
+ })
+ set.playTogether(outside_anim, inside_anim)
+ set.duration = 100
+ set.start()
+ }
+
+ //更新进度条
+ private fun updateProgress(millisUntilFinished: Long) {
+ recorded_time = (duration - millisUntilFinished).toInt()
+ progress = 360f - millisUntilFinished / duration.toFloat() * 360f
+ invalidate()
+ }
+
+ //录制视频计时器
+ private inner class RecordCountDownTimer internal constructor(
+ millisInFuture: Long,
+ countDownInterval: Long
+ ) :
+ CountDownTimer(millisInFuture, countDownInterval) {
+ override fun onTick(millisUntilFinished: Long) {
+ updateProgress(millisUntilFinished)
+ }
+
+ override fun onFinish() {
+ recordEnd()
+ }
+ }
+
+ //长按线程
+ private inner class LongPressRunnable : Runnable {
+ override fun run() {
+ state = STATE_LONG_PRESS //如果按下后经过500毫秒则会修改当前状态为长按状态
+ //启动按钮动画,外圆变大,内圆缩小
+ startRecordAnimation(
+ button_outside_radius,
+ button_outside_radius + outside_add_size,
+ button_inside_radius,
+ button_inside_radius - inside_reduce_size
+ )
+ }
+ }
+
+ /*************************************************** 对外提供的API**************************************/
+ /**
+ * 设置最长录制时间,,单位:秒
+ * 当到达设定的录制时长时,触发回调通知
+ */
+ fun setDuration(duration: Int) {
+ if (duration<1) {
+ return
+ }
+ this.duration = duration*1000L
+ timer = RecordCountDownTimer(this.duration, this.duration / 360) //录制定时器
+ }
+
+ //设置回调接口
+ fun setCaptureListener(captureListener: CaptureListener?) {
+ this.captureListener = captureListener
+ }
+
+ //设置按钮功能(拍照和录像)
+ fun setButtonFeatures(state: Int) {
+ buttonMode = state
+ }
+
+ //是否空闲状态
+ val isIdle: Boolean
+ get() = if (state == STATE_IDLE) true else false
+
+ //设置状态
+ fun resetState() {
+ state = STATE_IDLE
+ }
+
+ companion object {
+ // 选择拍照 拍视频 或者都有
+ const val BUTTON_STATE_ONLY_CAPTURE = 1 //只能拍照
+ const val BUTTON_STATE_ONLY_RECORDER = 2 //只能录像
+ const val BUTTON_STATE_BOTH = 3
+ const val BUTTON_STATE_BOTH_NOT = 4
+
+ //点击状态
+ const val STATE_IDLE = 0x001 //空闲状态
+ const val STATE_PRESS = 0x002 //按下状态
+ const val STATE_LONG_PRESS = 0x003 //长按状态
+
+ //事件
+ const val EVENT_IDLE = 0x001 //空闲状态
+ const val EVENT_RECORDERING = 0x002 //录制状态
+ const val EVENT_CAPTURE = 0x003 //拍照状态
+ }
+}
diff --git a/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/buttons/CaptureButton.java b/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/buttons/CaptureButton.java
deleted file mode 100644
index f1d8ce1..0000000
--- a/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/buttons/CaptureButton.java
+++ /dev/null
@@ -1,379 +0,0 @@
-package com.kiylx.camerax_lib.main.buttons;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.RectF;
-import android.os.CountDownTimer;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-
-import com.kiylx.camerax_lib.R;
-
-/**
- * 拍照按钮,拍视频动画
- * 点击拍照,长按录像
- *
- */
-public class CaptureButton extends View {
- // 选择拍照 拍视频 或者都有
- public static final int BUTTON_STATE_ONLY_CAPTURE = 0x101; //只能拍照
- public static final int BUTTON_STATE_ONLY_RECORDER = 0x102; //只能录像
- public static final int BUTTON_STATE_BOTH = 0x103;
-
- private int state; //当前按钮状态
- private int button_state = 240; //默认的大小不可用
-
- public static final int STATE_IDLE = 0x001; //空闲状态
- public static final int STATE_PRESS = 0x002; //按下状态
- public static final int STATE_LONG_PRESS = 0x003; //长按状态
- public static final int STATE_RECORDERING = 0x004; //录制状态
- public static final int STATE_BAN = 0x005; //禁止状态
-
- private int progress_color = 0xEE16AE16; //进度条颜色
- private int outside_color = 0xEEDCDCDC; //外圆背景色
- private int inside_color = 0xFFFFFFFF; //内圆背景色
-
- private float event_Y; //Touch_Event_Down时候记录的Y值
-
- private Paint mPaint;
-
- private float strokeWidth; //进度条宽度
- private int outside_add_size; //长按外圆半径变大的Size
- private int inside_reduce_size; //长安内圆缩小的Size
-
- //中心坐标
- private float center_X;
- private float center_Y;
-
- private float button_radius; //按钮半径
- private float button_outside_radius; //外圆半径
- private float button_inside_radius; //内圆半径
- private int button_size = 80; //按钮大小
-
- private float progress; //录制视频的进度
- private int duration = 15; //录制视频最大时间长度,秒
- private int recorded_time; //记录当前录制的时间
-
- private RectF rectF;
-
- private LongPressRunnable longPressRunnable; //长按后处理的逻辑Runnable
- private CaptureListener captureListener; //按钮回调接口
- private RecordCountDownTimer timer; //计时器
-
- public CaptureButton(Context context) {
- super(context);
- }
-
- /**
- * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
- */
- private int dip2px(Context context, float dpValue) {
- final float scale = context.getResources().getDisplayMetrics().density;
- return (int) (dpValue * scale + 0.5f);
- }
-
- /**
- * 总要支持一下XML 中布局吧
- *
- * @param context CONTEXT
- * @param attrs ATTRS
- */
- public CaptureButton(Context context, AttributeSet attrs) {
- super(context, attrs);
- TypedArray arr = getContext().obtainStyledAttributes(attrs, R.styleable.CaptureButton);
-
- this.button_size = dip2px(context, arr.getInteger(R.styleable.CaptureButton_size, button_size));
- this.duration = arr.getInteger(R.styleable.CaptureButton_maxDuration, duration)*1000;
-
- button_radius = button_size / 2.0f;
-
- button_outside_radius = button_radius;
- button_inside_radius = button_radius * 0.85f;
-
- strokeWidth = button_size / 15;
- outside_add_size = button_size / 8;
- inside_reduce_size = button_size / 8;
-
- mPaint = new Paint();
- mPaint.setAntiAlias(true);
-
- progress = 0;
- longPressRunnable = new LongPressRunnable();
-
- state = STATE_IDLE; //初始化为空闲状态
- button_state = BUTTON_STATE_BOTH; //初始化按钮为可录制可拍照
-
- center_X = (button_size + outside_add_size * 2) / 2;
- center_Y = (button_size + outside_add_size * 2) / 2;
-
- rectF = new RectF(
- center_X - (button_radius + outside_add_size - strokeWidth / 2),
- center_Y - (button_radius + outside_add_size - strokeWidth / 2),
- center_X + (button_radius + outside_add_size - strokeWidth / 2),
- center_Y + (button_radius + outside_add_size - strokeWidth / 2));
-
- timer = new RecordCountDownTimer(duration, duration / 360); //录制定时器
-
- arr.recycle();
- }
-
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- setMeasuredDimension(button_size + outside_add_size * 2, button_size + outside_add_size * 2);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- mPaint.setStyle(Paint.Style.FILL);
-
- mPaint.setColor(outside_color); //外圆(半透明灰色)
- canvas.drawCircle(center_X, center_Y, button_outside_radius, mPaint);
-
- mPaint.setColor(inside_color); //内圆(白色)
- canvas.drawCircle(center_X, center_Y, button_inside_radius, mPaint);
-
- //如果状态为录制状态,则绘制录制进度条
- if (state == STATE_RECORDERING) {
- mPaint.setColor(progress_color);
- mPaint.setStyle(Paint.Style.STROKE);
- mPaint.setStrokeWidth(strokeWidth);
- canvas.drawArc(rectF, -90, progress, false, mPaint);
- }
- }
-
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- if (event.getPointerCount() > 1 || state != STATE_IDLE)
- break;
- event_Y = event.getY(); //记录Y值
- state = STATE_PRESS; //修改当前状态为点击按下
-
- //判断按钮状态是否为可录制状态
- if ((button_state == BUTTON_STATE_ONLY_RECORDER || button_state == BUTTON_STATE_BOTH))
- postDelayed(longPressRunnable, 500); //同时延长500启动长按后处理的逻辑Runnable
- break;
- case MotionEvent.ACTION_MOVE:
- if (captureListener != null
- && state == STATE_RECORDERING
- && (button_state == BUTTON_STATE_ONLY_RECORDER || button_state == BUTTON_STATE_BOTH)) {
- //记录当前Y值与按下时候Y值的差值,调用缩放回调接口
- captureListener.recordZoom(event_Y - event.getY());
- }
- break;
- case MotionEvent.ACTION_UP:
- //根据当前按钮的状态进行相应的处理 ----CodeReview---抬起瞬间应该重置状态 当前状态可能为按下和正在录制
- //state = STATE_BAN;
- handlerPressByState();
- break;
- }
- return true;
- }
-
- //当手指松开按钮时候处理的逻辑
- private void handlerPressByState() {
- removeCallbacks(longPressRunnable); //移除长按逻辑的Runnable
- //根据当前状态处理
- switch (state) {
- //当前是点击按下
- case STATE_PRESS:
- if (captureListener != null && (button_state == BUTTON_STATE_ONLY_CAPTURE || button_state ==
- BUTTON_STATE_BOTH)) {
- startCaptureAnimation(button_inside_radius);
- } else {
- state = STATE_IDLE;
- }
- break;
- // ---CodeReview---当内外圆动画未结束时已经是长按状态 但还没有置为STATE_RECORDERING时 应该也要结束录制 此处是一个bug
- case STATE_LONG_PRESS:
- //当前是长按状态
- case STATE_RECORDERING:
- timer.cancel(); //停止计时器
- recordEnd(); //录制结束
- break;
- }
- state = STATE_IDLE;
- }
-
- //录制结束
- public void recordEnd() {
- if (captureListener != null) {
- captureListener.recordEnd(recorded_time); //回调录制结束
- }
- resetRecordAnim(); //重制按钮状态
- }
-
- //重制状态
- private void resetRecordAnim() {
- state = STATE_BAN;
- progress = 0; //重制进度
- invalidate();
- //还原按钮初始状态动画
- startRecordAnimation(
- button_outside_radius,
- button_radius,
- button_inside_radius,
- button_radius * 0.75f
- );
- }
-
- //内圆动画
- private void startCaptureAnimation(float inside_start) {
- ValueAnimator inside_anim = ValueAnimator.ofFloat(inside_start, inside_start * 0.75f, inside_start);
- inside_anim.addUpdateListener(animation -> {
- button_inside_radius = (float) animation.getAnimatedValue();
- invalidate();
- });
- inside_anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- //回调拍照接口
-// if (captureLisenter != null) {
-// captureLisenter.takePictures();
-// }
- // 为何拍照完成要将状态掷为禁止????此处貌似bug!!!!!!---CodeReview
- //state = STATE_BAN;
- //state = STATE_IDLE;
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- super.onAnimationStart(animation);
- if (captureListener != null) {
- captureListener.takePictures();
- }
- // 防止重复点击 状态重置
- state = STATE_BAN;
- }
- });
- inside_anim.setDuration(50);
- inside_anim.start();
- }
-
- //内外圆动画
- private void startRecordAnimation(float outside_start, float outside_end, float inside_start, float inside_end) {
- ValueAnimator outside_anim = ValueAnimator.ofFloat(outside_start, outside_end);
- ValueAnimator inside_anim = ValueAnimator.ofFloat(inside_start, inside_end);
- //外圆动画监听
- outside_anim.addUpdateListener(animation -> {
- button_outside_radius = (float) animation.getAnimatedValue();
- invalidate();
- });
- //内圆动画监听
- inside_anim.addUpdateListener(animation -> {
- button_inside_radius = (float) animation.getAnimatedValue();
- invalidate();
- });
- AnimatorSet set = new AnimatorSet();
- //当动画结束后启动录像Runnable并且回调录像开始接口
- set.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- //设置为录制状态
- if (state == STATE_LONG_PRESS) {
- if (captureListener != null)
- captureListener.recordStart();
- state = STATE_RECORDERING;
- timer.start();
- } else {
- // 此处动画包括长按起始动画和还原动画 若不是长按状态应该还原状态为空闲????---CodeReview
- state = STATE_IDLE;
- }
- }
- });
- set.playTogether(outside_anim, inside_anim);
- set.setDuration(100);
- set.start();
- }
-
-
- //更新进度条
- private void updateProgress(long millisUntilFinished) {
- recorded_time = (int) (duration - millisUntilFinished);
- progress = 360f - millisUntilFinished / (float) duration * 360f;
- invalidate();
- }
-
- //录制视频计时器
- private class RecordCountDownTimer extends CountDownTimer {
- RecordCountDownTimer(long millisInFuture, long countDownInterval) {
- super(millisInFuture, countDownInterval);
- }
-
- @Override
- public void onTick(long millisUntilFinished) {
- updateProgress(millisUntilFinished);
- }
-
- @Override
- public void onFinish() {
- //updateProgress(duration);
- recordEnd();
- }
- }
-
- //长按线程
- private class LongPressRunnable implements Runnable {
- @Override
- public void run() {
- state = STATE_LONG_PRESS; //如果按下后经过500毫秒则会修改当前状态为长按状态
- //启动按钮动画,外圆变大,内圆缩小
- startRecordAnimation(
- button_outside_radius,
- button_outside_radius + outside_add_size,
- button_inside_radius,
- button_inside_radius - inside_reduce_size
- );
- }
- }
-
- /**************************************************
- * 对外提供的API *
- **************************************************/
-
- //设置最长录制时间
- public void setDuration(int duration) {
- this.duration = duration;
- timer = new RecordCountDownTimer(duration, duration / 360); //录制定时器
- }
-
- //设置回调接口
- public void setCaptureListener(CaptureListener captureListener) {
- this.captureListener = captureListener;
- }
-
- //设置按钮功能(拍照和录像)
- public void setButtonFeatures(int state) {
- this.button_state = state;
- }
-
- // 获取当前按钮支持状态
- public int getButtonState() {
- return button_state;
- }
-
- //是否空闲状态
- public boolean isIdle() {
- return state == STATE_IDLE ? true : false;
- }
-
- //设置状态
- public void resetState() {
- state = STATE_IDLE;
- }
-
-}
diff --git a/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/buttons/CaptureButton2.java b/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/buttons/CaptureButton2.java
deleted file mode 100644
index a3878b7..0000000
--- a/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/buttons/CaptureButton2.java
+++ /dev/null
@@ -1,370 +0,0 @@
-package com.kiylx.camerax_lib.main.buttons;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.RectF;
-import android.os.CountDownTimer;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-
-import com.kiylx.camerax_lib.R;
-
-/**
- * 拍照按钮,拍视频动画
- * 指定app:captureMode="false" 则点击按钮为录像,否则点击为拍照
- */
-public class CaptureButton2 extends View {
- // 选择拍照 拍视频 或者都有
- public static final int BUTTON_STATE_ONLY_CAPTURE = 0x101; //只能拍照
- public static final int BUTTON_STATE_ONLY_RECORDER = 0x102; //只能录像
-
- private int state; //当前按钮状态
- private int button_state = 240; //默认的大小不可用
-
- public static final int STATE_IDLE = 0x001; //空闲状态
- public static final int STATE_PRESS = 0x002; //按下状态
- public static final int STATE_LONG_PRESS = 0x003; //长按状态
- public static final int STATE_RECORDERING = 0x004; //录制状态
- public static final int STATE_BAN = 0x005; //禁止状态
-
- private int progress_color = 0xEE16AE16; //进度条颜色
- private int outside_color = 0xEEDCDCDC; //外圆背景色
- private int inside_color = 0xFFFFFFFF; //内圆背景色
- private int inside_record_color = 0xFFFF1744; //内圆录制时背景色
-
-
- private float event_Y; //Touch_Event_Down时候记录的Y值
-
- private Paint mPaint;
-
- private float strokeWidth; //进度条宽度
- private int outside_add_size; //长按外圆半径变大的Size
- private int inside_reduce_size; //长安内圆缩小的Size
-
- //中心坐标
- private float center_X;
- private float center_Y;
-
- private float button_radius; //按钮半径
- private float button_outside_radius; //外圆半径
- private float button_inside_radius; //内圆半径
- private int button_size = 80; //按钮大小
-
- private int recorded_time; //记录当前录制的时间
-
- private RectF rectF;
-
- private LongPressRunnable longPressRunnable; //长按后处理的逻辑Runnable
- private CaptureListener captureListener; //按钮回调接口
- private RecordCountDownTimer timer; //计时器
- private int duration = 60 * 1000;
-
- public CaptureButton2(Context context) {
- super(context);
- }
-
- /**
- * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
- */
- private int dip2px(Context context, float dpValue) {
- final float scale = context.getResources().getDisplayMetrics().density;
- return (int) (dpValue * scale + 0.5f);
- }
-
- /**
- * 总要支持一下XML 中布局吧
- *
- * @param context CONTEXT
- * @param attrs ATTRS
- */
- public CaptureButton2(Context context, AttributeSet attrs) {
- super(context, attrs);
- TypedArray arr = getContext().obtainStyledAttributes(attrs, R.styleable.CaptureButton2);
-
- this.button_size = dip2px(context, arr.getInteger(R.styleable.CaptureButton_size, button_size));
- boolean mode = arr.getBoolean(R.styleable.CaptureButton2_captureMode, true);//拍照还是录像模式
-
- button_radius = button_size / 2.0f;
-
- button_outside_radius = button_radius;
- button_inside_radius = button_radius * 0.85f;
-
- strokeWidth = button_size / 15;
- outside_add_size = button_size / 8;
- inside_reduce_size = button_size / 8;
-
- mPaint = new Paint();
- mPaint.setAntiAlias(true);
-
- longPressRunnable = new LongPressRunnable();
-
- state = STATE_IDLE; //初始化为空闲状态
- if (mode) {
- button_state = BUTTON_STATE_ONLY_CAPTURE; //初始化按钮为拍照
- } else {
- button_state = BUTTON_STATE_ONLY_RECORDER; //初始化按钮为录制
- }
-
- center_X = (button_size + outside_add_size * 2) / 2;
- center_Y = (button_size + outside_add_size * 2) / 2;
-
- rectF = new RectF(
- center_X - (button_radius + outside_add_size - strokeWidth / 2),
- center_Y - (button_radius + outside_add_size - strokeWidth / 2),
- center_X + (button_radius + outside_add_size - strokeWidth / 2),
- center_Y + (button_radius + outside_add_size - strokeWidth / 2));
-
- timer = new RecordCountDownTimer(duration, duration / 360); //录制定时器
-
- arr.recycle();
- }
-
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- setMeasuredDimension(button_size + outside_add_size * 2, button_size + outside_add_size * 2);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- mPaint.setStyle(Paint.Style.FILL);
-
- mPaint.setColor(outside_color); //外圆(半透明灰色)
- canvas.drawCircle(center_X, center_Y, button_outside_radius, mPaint);
-
- mPaint.setColor(inside_color); //内圆(白色)
- canvas.drawCircle(center_X, center_Y, button_inside_radius, mPaint);
-
- //如果状态为录制状态,则绘制录制进度条
- if (state == STATE_RECORDERING) {
- mPaint.setColor(inside_record_color); //内圆(红色)
- canvas.drawCircle(center_X, center_Y, button_inside_radius, mPaint);
- }
- }
-
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- if (event.getPointerCount() > 1 || state != STATE_IDLE)
- break;
- event_Y = event.getY(); //记录Y值
- state = STATE_PRESS; //修改当前状态为点击按下
- break;
- case MotionEvent.ACTION_MOVE:
- if (captureListener != null
- && state == STATE_RECORDERING
- && (button_state == BUTTON_STATE_ONLY_RECORDER)) {
- //记录当前Y值与按下时候Y值的差值,调用缩放回调接口
- captureListener.recordZoom(event_Y - event.getY());
- }
- break;
- case MotionEvent.ACTION_UP:
- //根据当前按钮的状态进行相应的处理 ----CodeReview---抬起瞬间应该重置状态 当前状态可能为按下和正在录制
- //state = STATE_BAN;
- handlerPressByState();
- break;
- }
- return true;
- }
-
- //当手指松开按钮时候处理的逻辑
- private void handlerPressByState() {
- removeCallbacks(longPressRunnable); //移除长按逻辑的Runnable
- //根据当前状态处理
- switch (state) {
- //当前是点击按下
- case STATE_PRESS:
- if (captureListener != null && (button_state == BUTTON_STATE_ONLY_CAPTURE)) {
- //拍照
- startCaptureAnimation(button_inside_radius);
- } else if (captureListener != null && (button_state == BUTTON_STATE_ONLY_RECORDER)) {
- //录视频
- postDelayed(longPressRunnable, 500); //同时延长500启动长按后处理的逻辑Runnable
- } else {
- state = STATE_IDLE;
- }
- break;
- // ---CodeReview---当内外圆动画未结束时已经是长按状态 但还没有置为STATE_RECORDERING时 应该也要结束录制 此处是一个bug
- case STATE_LONG_PRESS:
- //当前是长按状态
- case STATE_RECORDERING:
- timer.cancel(); //停止计时器
- recordEnd(); //录制结束
- break;
- }
- state = STATE_IDLE;
- }
-
- //长按线程
- private class LongPressRunnable implements Runnable {
- @Override
- public void run() {
- state = STATE_LONG_PRESS; //如果按下后经过500毫秒则会修改当前状态为长按状态
- //启动按钮动画,外圆变大,内圆缩小
- startRecordAnimation(
- button_outside_radius,
- button_outside_radius + outside_add_size,
- button_inside_radius,
- button_inside_radius - inside_reduce_size
- );
- }
- }
-
- //录制结束
- public void recordEnd() {
- if (captureListener != null) {
- captureListener.recordEnd(recorded_time); //回调录制结束
- }
- resetRecordAnim(); //重制按钮状态
- }
-
- //重制状态
- private void resetRecordAnim() {
- state = STATE_BAN;
- invalidate();
- //还原按钮初始状态动画
- startRecordAnimation(
- button_outside_radius,
- button_radius,
- button_inside_radius,
- button_radius * 0.75f
- );
- }
-
- //内圆动画
- private void startCaptureAnimation(float inside_start) {
- ValueAnimator inside_anim = ValueAnimator.ofFloat(inside_start, inside_start * 0.75f, inside_start);
- inside_anim.addUpdateListener(animation -> {
- button_inside_radius = (float) animation.getAnimatedValue();
- invalidate();
- });
- inside_anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- //回调拍照接口
-// if (captureLisenter != null) {
-// captureLisenter.takePictures();
-// }
- // 为何拍照完成要将状态掷为禁止????此处貌似bug!!!!!!---CodeReview
- //state = STATE_BAN;
- //state = STATE_IDLE;
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- super.onAnimationStart(animation);
- if (captureListener != null) {
- captureListener.takePictures();
- }
- // 防止重复点击 状态重置
- state = STATE_BAN;
- }
- });
- inside_anim.setDuration(50);
- inside_anim.start();
- }
-
- //内外圆动画
- private void startRecordAnimation(float outside_start, float outside_end, float inside_start, float inside_end) {
- ValueAnimator outside_anim = ValueAnimator.ofFloat(outside_start, outside_end);
- ValueAnimator inside_anim = ValueAnimator.ofFloat(inside_start, inside_end);
- //外圆动画监听
- outside_anim.addUpdateListener(animation -> {
- button_outside_radius = (float) animation.getAnimatedValue();
- invalidate();
- });
- //内圆动画监听
- inside_anim.addUpdateListener(animation -> {
- button_inside_radius = (float) animation.getAnimatedValue();
- invalidate();
- });
- AnimatorSet set = new AnimatorSet();
- //当动画结束后启动录像Runnable并且回调录像开始接口
- set.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- //设置为录制状态
- if (state == STATE_LONG_PRESS) {
- if (captureListener != null)
- captureListener.recordStart();
- state = STATE_RECORDERING;
- timer.start();
- } else {
- // 此处动画包括长按起始动画和还原动画 若不是长按状态应该还原状态为空闲????---CodeReview
- state = STATE_IDLE;
- }
- }
- });
- set.playTogether(outside_anim, inside_anim);
- set.setDuration(100);
- set.start();
- }
-
-
- //录制视频计时器
- private class RecordCountDownTimer extends CountDownTimer {
- RecordCountDownTimer(long millisInFuture, long countDownInterval) {
- super(millisInFuture, countDownInterval);
- }
-
- @Override
- public void onTick(long millisUntilFinished) {
- }
-
- @Override
- public void onFinish() {
- //updateProgress(duration);
- recordEnd();
- }
- }
-
-
- /**************************************************
- * 对外提供的API *
- **************************************************/
-
- //设置最长录制时间
- public void setDuration(int duration) {
- this.duration = duration;
- timer = new RecordCountDownTimer(duration, duration / 360); //录制定时器
- }
-
- //设置回调接口
- public void setCaptureListener(CaptureListener captureListener) {
- this.captureListener = captureListener;
- }
-
- //设置按钮功能(拍照和录像)
- public void setButtonFeatures(int state) {
- this.button_state = state;
- }
-
- // 获取当前按钮支持状态
- public int getButtonState() {
- return button_state;
- }
-
- //是否空闲状态
- public boolean isIdle() {
- return state == STATE_IDLE ? true : false;
- }
-
- //设置状态
- public void resetState() {
- state = STATE_IDLE;
- }
-
-}
diff --git a/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/buttons/CaptureListener.kt b/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/buttons/CaptureListener.kt
index d3c5706..0085cd8 100644
--- a/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/buttons/CaptureListener.kt
+++ b/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/buttons/CaptureListener.kt
@@ -7,9 +7,15 @@ interface CaptureListener {
fun takePictures()
+ /**
+ * 回调此方法以通知可以开始录制
+ */
fun recordStart()
- fun recordEnd(time: Long)
+ /**
+ * 到达设定的录制时长时,将回调此方法通知可以结束录制了
+ */
+ fun recordShouldEnd(time: Long)
fun recordZoom(zoom: Float)
@@ -29,7 +35,7 @@ open class DefaultCaptureListener :CaptureListener{
}
- override fun recordEnd(time: Long) {
+ override fun recordShouldEnd(time: Long) {
}
diff --git a/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/manager/CameraXManager.kt b/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/manager/CameraXManager.kt
index adaebb1..0c7381a 100644
--- a/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/manager/CameraXManager.kt
+++ b/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/manager/CameraXManager.kt
@@ -31,7 +31,7 @@ import com.kiylx.camerax_lib.main.manager.model.*
import com.kiylx.camerax_lib.main.manager.video.VideoRecorderHolder
import com.kiylx.camerax_lib.main.store.StorageConfig
import com.kiylx.camerax_lib.view.CameraXPreviewViewTouchListener
-import com.yeyupiaoling.cameraxapp.view.FocusImageView
+import com.kiylx.camerax_lib.view.FocusImageView
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
@@ -511,7 +511,7 @@ abstract class CameraXManager(
/** 更新用例的方向 */
@CallSuper
open fun updateCaseRotation(rotation: Int) {
- Log.e("旋转1", "$rotation")
+// Log.e("旋转1", "$rotation")
//横屏时,动态设置他们的方向
imageAnalyzer.targetRotation = rotation
imageCapture.targetRotation = rotation
diff --git a/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/ui/BaseCameraXActivity.kt b/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/ui/BaseCameraXActivity.kt
index 5245ef0..b60d8d3 100644
--- a/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/ui/BaseCameraXActivity.kt
+++ b/camerax_lib/src/main/java/com/kiylx/camerax_lib/main/ui/BaseCameraXActivity.kt
@@ -14,6 +14,7 @@ import com.blankj.utilcode.util.LogUtils
import com.kiylx.camerax_lib.R
import com.kiylx.camerax_lib.databinding.ActivityCameraExampleBinding
import com.kiylx.camerax_lib.main.buttons.CaptureListener
+import com.kiylx.camerax_lib.main.buttons.DefaultCaptureListener
import com.kiylx.camerax_lib.main.manager.CameraHolder
import com.kiylx.camerax_lib.main.manager.KEY_CAMERA_EVENT_ACTION
import com.kiylx.camerax_lib.main.manager.KEY_CAMERA_EVENT_EXTRA
@@ -175,48 +176,40 @@ abstract class BaseCameraXActivity : BasicActivity(),
//相机初始化完成
open fun initCameraFinished() {
//拍照,拍视频的UI 操作的各种状态处理
- page.captureBtn2.setCaptureListener(object : CaptureListener {
+ page.fullCaptureBtn.setCaptureListener(object : DefaultCaptureListener(){
override fun takePictures() {
cameraXFragment.takePhoto()
}
-
//开始录制视频
override fun recordStart() {
-
- }
-
- //录制视频结束
- override fun recordEnd(time: Long) {
-
- }
-
- //长按拍视频的时候,在屏幕滑动可以调整焦距缩放
- override fun recordZoom(zoom: Float) {
- val a = zoom
+ page.captureVideoBtn.visibility = View.GONE
+ LogUtils.dTag("录制activity", "开始")
+ cameraXFragment.takeVideo()
+ //录制视频时隐藏摄像头切换
+ page.switchBtn.visibility=View.GONE
}
- //录制视频错误(拍照也会有错误,先不处理了吧)
- override fun recordError(message: String) {
-
+ //录制视频到达预定的时长,可以结束了
+ override fun recordShouldEnd(time: Long) {
+ page.captureVideoBtn.visibility = View.VISIBLE
+ LogUtils.dTag("录制activity", "停止")
+ cameraXFragment.stopTakeVideo(time)
+ page.switchBtn.visibility=View.VISIBLE
}
})
- page.captureVideoBtn.setCaptureListener(object : CaptureListener {
- override fun takePictures() {
-
- }
-
+ page.captureVideoBtn.setCaptureListener(object : DefaultCaptureListener(){
//开始录制视频
override fun recordStart() {
- page.captureBtn2.visibility = View.GONE
+ page.fullCaptureBtn.visibility = View.GONE
LogUtils.dTag("录制activity", "开始")
cameraXFragment.takeVideo()
//录制视频时隐藏摄像头切换
page.switchBtn.visibility=View.GONE
}
- //录制视频结束
- override fun recordEnd(time: Long) {
- page.captureBtn2.visibility = View.VISIBLE
+ //录制视频到达预定的时长,可以结束了
+ override fun recordShouldEnd(time: Long) {
+ page.fullCaptureBtn.visibility = View.VISIBLE
LogUtils.dTag("录制activity", "停止")
cameraXFragment.stopTakeVideo(time)
page.switchBtn.visibility=View.VISIBLE
diff --git a/camerax_lib/src/main/java/com/kiylx/camerax_lib/view/FocusImageView.kt b/camerax_lib/src/main/java/com/kiylx/camerax_lib/view/FocusImageView.kt
index 3acf837..eb2b9d5 100644
--- a/camerax_lib/src/main/java/com/kiylx/camerax_lib/view/FocusImageView.kt
+++ b/camerax_lib/src/main/java/com/kiylx/camerax_lib/view/FocusImageView.kt
@@ -1,4 +1,4 @@
-package com.yeyupiaoling.cameraxapp.view
+package com.kiylx.camerax_lib.view
import android.content.Context
import android.graphics.Point
diff --git a/camerax_lib/src/main/res/layout/activity_camera_example.xml b/camerax_lib/src/main/res/layout/activity_camera_example.xml
index 1bda476..4f92b53 100644
--- a/camerax_lib/src/main/res/layout/activity_camera_example.xml
+++ b/camerax_lib/src/main/res/layout/activity_camera_example.xml
@@ -152,21 +152,24 @@
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
-
-
-
-
-
+
+
-
+
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/camerax_lib/src/main/res/values/ids.xml b/camerax_lib/src/main/res/values/ids.xml
index e8eaf96..36809af 100644
--- a/camerax_lib/src/main/res/values/ids.xml
+++ b/camerax_lib/src/main/res/values/ids.xml
@@ -3,6 +3,6 @@
-
+
\ No newline at end of file