Skip to content

Commit 05a0dfd

Browse files
committed
✨ Add enablePullToZoomInRecord
1 parent 2e3ea86 commit 05a0dfd

File tree

3 files changed

+61
-18
lines changed

3 files changed

+61
-18
lines changed

README-ZH.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,11 @@ Flutter SDK:`>=1.20.0` 。
4949
| ---------------------------- | ------------------------------ | ---------------------------------------------------------------- | -------------------------------------- |
5050
| enableRecording | `bool` | 选择器是否可以录像 | `false` |
5151
| onlyEnableRecording | `bool` | 选择器是否仅可以录像。只在 `enableRecording``true` 时有效。 | `false` |
52-
| enabledAudio | `bool` | 选择器是否需要录制音频。只于录像配合有效。 | `true` |
52+
| enableAudio | `bool` | 选择器是否需要录制音频。只于录像配合有效。 | `true` |
5353
| enableSetExposure | `bool` | 用户是否可以在界面上通过点击设定曝光点 | `true` |
5454
| enableExposureControlOnPoint | `bool` | 用户是否可以根据已经设置的曝光点调节曝光度 | `true` |
5555
| enablePinchToZoom | `bool` | 用户是否可以在界面上双指缩放相机对焦 | `true` |
56+
| enablePullToZoomInRecord | `bool` | 用户是否可以在录制视频时上拉缩放 | `true` |
5657
| shouldDeletePreviewFile | `bool` | 返回页面时是否删除预览文件 | `false` |
5758
| maximumRecordingDuration | `Duration` | 录制视频最长时长 | `const Duration(seconds: 15)` |
5859
| theme | `ThemeData` | 选择器的主题 | `CameraPicker.themeData(C.themeColor)` |

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ Reference:
7979
| enableSetExposure | `bool` | Whether users can set the exposure point by tapping. | `true` |
8080
| enableExposureControlOnPoint | `bool` | Whether users can adjust exposure according to the set point. | `true` |
8181
| enablePinchToZoom | `bool` | Whether users can zoom the camera by pinch. | `true` |
82+
| enablePullToZoomInRecord | `bool` | Whether users can zoom by pulling up when recording video. | `true` |
8283
| shouldDeletePreviewFile | `bool` | Whether the preview file will be delete when pop. | `false` |
8384
| maximumRecordingDuration | `Duration` | The maximum duration of the video recording process. | `const Duration(seconds: 15)` |
8485
| theme | `ThemeData` | Theme data for the picker. | `CameraPicker.themeData(C.themeColor)` |

lib/src/widget/camera_picker.dart

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class CameraPicker extends StatefulWidget {
3535
this.enableSetExposure = true,
3636
this.enableExposureControlOnPoint = true,
3737
this.enablePinchToZoom = true,
38+
this.enablePullToZoomInRecord = true,
3839
this.shouldDeletePreviewFile = false,
3940
this.maximumRecordingDuration = const Duration(seconds: 15),
4041
this.theme,
@@ -47,6 +48,7 @@ class CameraPicker extends StatefulWidget {
4748
assert(onlyEnableRecording != null),
4849
assert(enableAudio != null),
4950
assert(enablePinchToZoom != null),
51+
assert(enablePullToZoomInRecord != null),
5052
assert(enableSetExposure != null),
5153
assert(enableExposureControlOnPoint != null),
5254
assert(shouldDeletePreviewFile != null),
@@ -96,6 +98,10 @@ class CameraPicker extends StatefulWidget {
9698
/// 用户是否可以在界面上双指缩放相机对焦
9799
final bool enablePinchToZoom;
98100

101+
/// Whether users can zoom by pulling up when recording video.
102+
/// 用户是否可以在录制视频时上拉缩放
103+
final bool enablePullToZoomInRecord;
104+
99105
/// Whether the preview file will be delete when pop.
100106
/// 返回页面时是否删除预览文件
101107
final bool shouldDeletePreviewFile;
@@ -235,6 +241,10 @@ class CameraPickerState extends State<CameraPicker>
235241
/// 最后一次手动聚焦的点坐标
236242
final ValueNotifier<Offset> _lastExposurePoint = ValueNotifier<Offset>(null);
237243

244+
/// The last pressed position on the shooting button before starts recording.
245+
/// 在开始录像前,最后一次在拍照按钮按下的位置
246+
Offset _lastShootingButtonPressedPosition;
247+
238248
/// Current exposure mode.
239249
/// 当前曝光模式
240250
final ValueNotifier<ExposureMode> _exposureMode =
@@ -337,6 +347,8 @@ class CameraPickerState extends State<CameraPicker>
337347

338348
bool get enablePinchToZoom => widget.enablePinchToZoom;
339349

350+
bool get enablePullToZoomInRecord => widget.enablePullToZoomInRecord;
351+
340352
bool get shouldDeletePreviewFile => widget.shouldDeletePreviewFile;
341353

342354
/// Getter for `widget.maximumRecordingDuration` .
@@ -534,25 +546,33 @@ class CameraPickerState extends State<CameraPicker>
534546
}
535547
}
536548

549+
Future<void> zoom(double scale) async {
550+
final double _zoom = (_baseZoom * scale)
551+
.clamp(_minAvailableZoom, _maxAvailableZoom)
552+
.toDouble();
553+
if (_zoom == _currentZoom) {
554+
return;
555+
}
556+
_currentZoom = _zoom;
557+
558+
await controller.setZoomLevel(_currentZoom);
559+
}
560+
537561
/// Handle when the scale gesture start.
538562
/// 处理缩放开始的手势
539563
void _handleScaleStart(ScaleStartDetails details) {
540564
_baseZoom = _currentZoom;
541565
}
542566

543-
/// Handle when the scale details is updating.
544-
/// 处理缩放更新
567+
/// Handle when the double tap scale details is updating.
568+
/// 处理双指缩放更新
545569
Future<void> _handleScaleUpdate(ScaleUpdateDetails details) async {
546570
// When there are not exactly two fingers on screen don't scale
547571
if (_pointers != 2) {
548572
return;
549573
}
550574

551-
_currentZoom = (_baseZoom * details.scale)
552-
.clamp(_minAvailableZoom, _maxAvailableZoom)
553-
.toDouble();
554-
555-
await controller.setZoomLevel(_currentZoom);
575+
zoom(details.scale);
556576
}
557577

558578
void _restartPointDisplayTimer() {
@@ -644,6 +664,20 @@ class CameraPickerState extends State<CameraPicker>
644664
_restartPointDisplayTimer();
645665
}
646666

667+
void onShootingButtonMove(PointerMoveEvent event) {
668+
_lastShootingButtonPressedPosition ??= event.position;
669+
if (controller.value.isRecordingVideo) {
670+
// First calculate relative offset.
671+
final Offset _offset =
672+
event.position - _lastShootingButtonPressedPosition;
673+
// Then turn negative,
674+
// multiply double with 10 * 1.5 - 1 = 14,
675+
// plus 1 to ensure always scale.
676+
final double _scale = _offset.dy / Screens.height * -14 + 1;
677+
zoom(_scale);
678+
}
679+
}
680+
647681
/// The method to take a picture.
648682
/// 拍照方法
649683
///
@@ -696,6 +730,7 @@ class CameraPickerState extends State<CameraPicker>
696730
void recordDetectionCancel(PointerUpEvent event) {
697731
_recordDetectTimer?.cancel();
698732
if (controller.value.isRecordingVideo) {
733+
_lastShootingButtonPressedPosition = null;
699734
stopRecordingVideo();
700735
safeSetState(() {});
701736
}
@@ -760,17 +795,22 @@ class CameraPickerState extends State<CameraPicker>
760795
/// This displayed at the top of the screen.
761796
/// 该区域显示在屏幕上方。
762797
Widget get settingsAction {
763-
return Padding(
764-
padding: const EdgeInsets.symmetric(horizontal: 12.0),
765-
child: Row(
766-
children: <Widget>[
767-
if ((cameras?.length ?? 0) > 1) switchCamerasButton,
768-
const Spacer(),
769-
_initializeWrapper(
770-
builder: (CameraValue v, __) => switchFlashesButton(v),
798+
return _initializeWrapper(
799+
builder: (CameraValue v, __) {
800+
if (v.isRecordingVideo) {
801+
return const SizedBox.shrink();
802+
}
803+
return Padding(
804+
padding: const EdgeInsets.symmetric(horizontal: 12.0),
805+
child: Row(
806+
children: <Widget>[
807+
if ((cameras?.length ?? 0) > 1) switchCamerasButton,
808+
const Spacer(),
809+
switchFlashesButton(v),
810+
],
771811
),
772-
],
773-
),
812+
);
813+
},
774814
);
775815
}
776816

@@ -881,6 +921,7 @@ class CameraPickerState extends State<CameraPicker>
881921
return Listener(
882922
behavior: HitTestBehavior.opaque,
883923
onPointerUp: enableRecording ? recordDetectionCancel : null,
924+
onPointerMove: enablePullToZoomInRecord ? onShootingButtonMove : null,
884925
child: InkWell(
885926
borderRadius: maxBorderRadius,
886927
onTap: !onlyEnableRecording ? takePicture : null,

0 commit comments

Comments
 (0)