CaptureButton.java
14.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
package com.cjt2325.cameralibrary;
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.view.MotionEvent;
import android.view.View;
import com.cjt2325.cameralibrary.listener.CaptureListener;
import com.cjt2325.cameralibrary.util.CheckPermission;
import com.cjt2325.cameralibrary.util.LogUtil;
import static com.cjt2325.cameralibrary.JCameraView.BUTTON_STATE_BOTH;
import static com.cjt2325.cameralibrary.JCameraView.BUTTON_STATE_ONLY_CAPTURE;
import static com.cjt2325.cameralibrary.JCameraView.BUTTON_STATE_ONLY_RECORDER;
/**
* =====================================
* 作 者: 陈嘉桐 445263848@qq.com
* 版 本:1.1.4
* 创建日期:2017/4/25
* 描 述:拍照按钮
* =====================================
*/
public class CaptureButton extends View {
private int state; //当前按钮状态
private int button_state; //按钮可执行的功能状态(拍照,录制,两者)
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; //按钮大小
private float progress; //录制视频的进度
private int duration; //录制视频最大时间长度
private int min_duration; //最短录制时间限制
private int recorded_time; //记录当前录制的时间
private RectF rectF;
private LongPressRunnable longPressRunnable; //长按后处理的逻辑Runnable
private CaptureListener captureLisenter; //按钮回调接口
private RecordCountDownTimer timer; //计时器
public CaptureButton(Context context) {
super(context);
}
public CaptureButton(Context context, int size) {
super(context);
this.button_size = size;
button_radius = size / 2.0f;
button_outside_radius = button_radius;
button_inside_radius = button_radius * 0.75f;
strokeWidth = size / 15;
outside_add_size = size / 5;
inside_reduce_size = size / 8;
mPaint = new Paint();
mPaint.setAntiAlias(true);
progress = 0;
longPressRunnable = new LongPressRunnable();
state = STATE_IDLE; //初始化为空闲状态
button_state = BUTTON_STATE_BOTH; //初始化按钮为可录制可拍照
LogUtil.i("CaptureButtom start");
duration = 10 * 1000; //默认最长录制时间为10s
LogUtil.i("CaptureButtom end");
min_duration = 1500; //默认最短录制时间为1.5s
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));
center_X - (button_radius - strokeWidth / 2),
center_Y - (button_radius - strokeWidth / 2),
center_X + (button_radius - strokeWidth / 2),
center_Y + (button_radius - strokeWidth / 2));
timer = new RecordCountDownTimer(duration, duration / 360); //录制定时器
}
@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 (button_state == BUTTON_STATE_ONLY_RECORDER && state == STATE_RECORDERING) {
timer.cancel(); //停止计时器
recordEnd(); //录制结束
} else {
LogUtil.i("state = " + state);
if (event.getPointerCount() > 1 || state != STATE_IDLE)
break;
event_Y = event.getY(); //记录Y值
state = STATE_PRESS; //修改当前状态为点击按下
//判断按钮状态是否为可录制状态
if (button_state == BUTTON_STATE_ONLY_RECORDER) {
postDelayed(longPressRunnable, 0); //同时延长500启动长按后处理的逻辑Runnable
} else if ((button_state == BUTTON_STATE_ONLY_RECORDER || button_state == BUTTON_STATE_BOTH))
postDelayed(longPressRunnable, 500); //同时延长500启动长按后处理的逻辑Runnable
}
break;
case MotionEvent.ACTION_MOVE:
if (captureLisenter != null
&& state == STATE_RECORDERING
&& (button_state == BUTTON_STATE_ONLY_RECORDER || button_state == BUTTON_STATE_BOTH)) {
//记录当前Y值与按下时候Y值的差值,调用缩放回调接口
captureLisenter.recordZoom(event_Y - event.getY());
}
break;
case MotionEvent.ACTION_UP:
if (button_state != BUTTON_STATE_ONLY_RECORDER) {
//根据当前按钮的状态进行相应的处理
handlerUnpressByState();
}
break;
}
return true;
}
//当手指松开按钮时候处理的逻辑
private void handlerUnpressByState() {
removeCallbacks(longPressRunnable); //移除长按逻辑的Runnable
//根据当前状态处理
switch (state) {
//当前是点击按下
case STATE_PRESS:
if (captureLisenter != null && (button_state == BUTTON_STATE_ONLY_CAPTURE || button_state ==
BUTTON_STATE_BOTH)) {
startCaptureAnimation(button_inside_radius);
} else {
state = STATE_IDLE;
}
break;
//当前是长按状态
case STATE_RECORDERING:
timer.cancel(); //停止计时器
recordEnd(); //录制结束
break;
}
}
//录制结束
private void recordEnd() {
if (captureLisenter != null) {
if (recorded_time < min_duration)
captureLisenter.recordShort(recorded_time);//回调录制时间过短
else
captureLisenter.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(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
button_inside_radius = (float) animation.getAnimatedValue();
invalidate();
}
});
inside_anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
//回调拍照接口
captureLisenter.takePictures();
state = STATE_BAN;
}
});
inside_anim.setDuration(100);
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(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
button_outside_radius = (float) animation.getAnimatedValue();
invalidate();
}
});
//内圆动画监听
inside_anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator 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 (captureLisenter != null)
captureLisenter.recordStart();
state = STATE_RECORDERING;
timer.start();
}
}
});
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(0);
recordEnd();
}
}
//长按线程
private class LongPressRunnable implements Runnable {
@Override
public void run() {
state = STATE_LONG_PRESS; //如果按下后经过500毫秒则会修改当前状态为长按状态
//没有录制权限
if (CheckPermission.getRecordState() != CheckPermission.STATE_SUCCESS) {
state = STATE_IDLE;
if (captureLisenter != null) {
captureLisenter.recordError();
return;
}
}
//启动按钮动画,外圆变大,内圆缩小
startRecordAnimation(
button_outside_radius,
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 setMinDuration(int duration) {
this.min_duration = duration;
}
//设置回调接口
public void setCaptureLisenter(CaptureListener captureLisenter) {
this.captureLisenter = captureLisenter;
}
//设置按钮功能(拍照和录像)
public void setButtonFeatures(int state) {
this.button_state = state;
}
//是否空闲状态
public boolean isIdle() {
return state == STATE_IDLE ? true : false;
}
//设置状态
public void resetState() {
state = STATE_IDLE;
}
}