瀏覽代碼

修改CameraPicker插件,拉到本地修改,设置ValueListenableBuilder<CameraValue> 的监听之后布局的重绘强制使用 lockedCaptureOrientation 的方向判断来替代 deviceOrientation 的方向。
那么以后使用此本地库的时候就需要强制定义 lockedCaptureOrientation 属性。

经过测试iOS可以保持相机的垂直拍摄了

liukai 3 天之前
父節點
當前提交
6d60e78560

+ 0 - 2
app/ios/Runner/Runner.entitlements

@@ -10,7 +10,5 @@
 	</array>
 	<key>com.apple.developer.associated-domains</key>
 	<array/>
-	<key>com.apple.developer.networking.wifi-info</key>
-	<true/>
 </dict>
 </plist>

+ 57 - 87
app/plugin_wechat_camera_picker/lib/src/states/camera_picker_state.dart

@@ -30,8 +30,7 @@ import '../widgets/camera_progress_button.dart';
 const Color _lockedColor = Colors.orangeAccent;
 const Duration _kDuration = Duration(milliseconds: 300);
 
-class CameraPickerState extends State<CameraPicker>
-    with WidgetsBindingObserver {
+class CameraPickerState extends State<CameraPicker> with WidgetsBindingObserver {
   /// The controller for the current camera.
   /// 当前相机实例的控制器
   CameraController get controller => innerController!;
@@ -72,8 +71,7 @@ class CameraPickerState extends State<CameraPicker>
   /// Current exposure offset.
   /// 当前曝光值
   final ValueNotifier<double> currentExposureOffset = ValueNotifier<double>(0);
-  final ValueNotifier<double> currentExposureSliderOffset =
-      ValueNotifier<double>(0);
+  final ValueNotifier<double> currentExposureSliderOffset = ValueNotifier<double>(0);
   double maxAvailableExposureOffset = 0;
   double minAvailableExposureOffset = 0;
   double exposureStep = 0;
@@ -141,8 +139,7 @@ class CameraPickerState extends State<CameraPicker>
   /// not valid, it is removed from the list.
   /// 使用每个相机的所有闪光灯模式进行初始化。
   /// 如果闪光灯模式无效,则将其从列表中删除。
-  final Map<CameraDescription, List<FlashMode>> validFlashModes =
-      <CameraDescription, List<FlashMode>>{};
+  final Map<CameraDescription, List<FlashMode>> validFlashModes = <CameraDescription, List<FlashMode>>{};
 
   ////////////////////////////////////////////////////////////////////////////
   ////////////////////////////// Global Getters //////////////////////////////
@@ -159,13 +156,11 @@ class CameraPickerState extends State<CameraPicker>
 
   /// Whether the picker only enables video recording.
   /// 选择器是否只可以录像
-  bool get onlyEnableRecording =>
-      enableRecording && pickerConfig.onlyEnableRecording;
+  bool get onlyEnableRecording => enableRecording && pickerConfig.onlyEnableRecording;
 
   /// Whether allow the record can start with single tap.
   /// 选择器是否可以单击录像
-  bool get enableTapRecording =>
-      onlyEnableRecording && pickerConfig.enableTapRecording;
+  bool get enableTapRecording => onlyEnableRecording && pickerConfig.enableTapRecording;
 
   /// No audio integration required when it's only for camera.
   /// 在仅允许拍照时不需要启用音频
@@ -173,16 +168,13 @@ class CameraPickerState extends State<CameraPicker>
 
   /// Whether the picker needs to prepare for video recording on iOS.
   /// 是否需要为 iOS 的录制视频执行准备操作
-  bool get shouldPrepareForVideoRecording =>
-      enableRecording && enableAudio && Platform.isIOS;
+  bool get shouldPrepareForVideoRecording => enableRecording && enableAudio && Platform.isIOS;
 
-  bool get enablePullToZoomInRecord =>
-      enableRecording && pickerConfig.enablePullToZoomInRecord;
+  bool get enablePullToZoomInRecord => enableRecording && pickerConfig.enablePullToZoomInRecord;
 
   /// Whether the recording restricted to a specific duration.
   /// 录像是否有限制的时长
-  bool get isRecordingRestricted =>
-      pickerConfig.maximumRecordingDuration != null;
+  bool get isRecordingRestricted => pickerConfig.maximumRecordingDuration != null;
 
   /// The minimum recording duration limit.
   /// 录制视频的最短时长限制。
@@ -190,9 +182,7 @@ class CameraPickerState extends State<CameraPicker>
   /// If the maximum duration is less than the minimum, use the maximum instead.
   /// 如果最大时长大于最小时长,则使用最大时长。
   Duration get minimumRecordingDuration {
-    if (pickerConfig.maximumRecordingDuration != null &&
-        pickerConfig.maximumRecordingDuration! <
-            pickerConfig.minimumRecordingDuration) {
+    if (pickerConfig.maximumRecordingDuration != null && pickerConfig.maximumRecordingDuration! < pickerConfig.minimumRecordingDuration) {
       return pickerConfig.maximumRecordingDuration!;
     }
     return pickerConfig.minimumRecordingDuration;
@@ -202,9 +192,7 @@ class CameraPickerState extends State<CameraPicker>
   bool get isRecordingVideo => innerController?.value.isRecordingVideo ?? false;
 
   /// Whether the capture button is displaying.
-  bool get shouldCaptureButtonDisplay =>
-      (isCaptureButtonTapDown || MediaQuery.accessibleNavigationOf(context)) &&
-      isRecordingVideo;
+  bool get shouldCaptureButtonDisplay => (isCaptureButtonTapDown || MediaQuery.accessibleNavigationOf(context)) && isRecordingVideo;
 
   /// Whether the camera preview should be rotated.
   bool get isCameraRotated => pickerConfig.cameraQuarterTurns % 4 != 0;
@@ -217,8 +205,7 @@ class CameraPickerState extends State<CameraPicker>
 
   /// If there's no theme provided from the user, use [CameraPicker.themeData] .
   /// 如果用户未提供主题,通过 [CameraPicker.themeData] 创建。
-  late final ThemeData theme =
-      pickerConfig.theme ?? CameraPicker.themeData(defaultThemeColorWeChat);
+  late final ThemeData theme = pickerConfig.theme ?? CameraPicker.themeData(defaultThemeColorWeChat);
 
   CameraPickerTextDelegate get textDelegate => Singleton.textDelegate;
 
@@ -260,6 +247,12 @@ class CameraPickerState extends State<CameraPicker>
   @override
   void initState() {
     super.initState();
+
+    SystemChrome.setPreferredOrientations([
+      DeviceOrientation.portraitUp,
+      // DeviceOrientation.landscapeLeft,
+      // DeviceOrientation.landscapeRight,
+    ]);
     ambiguate(WidgetsBinding.instance)?.addObserver(this);
     Singleton.textDelegate = widget.pickerConfig.textDelegate ?? cameraPickerTextDelegateFromLocale(widget.locale);
     initCameras();
@@ -313,12 +306,11 @@ class CameraPickerState extends State<CameraPicker>
       return 1;
     }
     final int turns = cameraQuarterTurns;
-    final String orientation = controller.value.deviceOrientation.toString();
+    final String orientation = controller.value.lockedCaptureOrientation.toString();
     // Fetch the biggest size from the constraints.
     Size size = constraints.biggest;
     // Flip the size when the preview needs to turn with an odd count of quarters.
-    if ((turns.isOdd && orientation.contains('portrait')) ||
-        (turns.isEven && orientation.contains('landscape'))) {
+    if ((turns.isOdd && orientation.contains('portrait')) || (turns.isEven && orientation.contains('landscape'))) {
       size = size.flipped;
     }
     // Calculate scale depending on the size and camera ratios.
@@ -416,8 +408,7 @@ class CameraPickerState extends State<CameraPicker>
 
       initFlashModesForCameras();
       final int preferredIndex = cameras.indexWhere(
-        (CameraDescription e) =>
-            e.lensDirection == pickerConfig.preferredLensDirection,
+        (CameraDescription e) => e.lensDirection == pickerConfig.preferredLensDirection,
       );
       final int index;
       if (preferredIndex != -1 && c == null) {
@@ -505,8 +496,7 @@ class CameraPickerState extends State<CameraPicker>
             if (camera.lensDirection != CameraLensDirection.front)
               Future(() async {
                 final flashMode = pickerConfig.preferredFlashMode;
-                if (flashMode != FlashMode.auto &&
-                    validFlashModes[camera]?.contains(flashMode) != false) {
+                if (flashMode != FlashMode.auto && validFlashModes[camera]?.contains(flashMode) != false) {
                   return wrapControllerMethod<void>(
                     'setFlashMode',
                     () => newController.setFlashMode(flashMode),
@@ -596,11 +586,12 @@ class CameraPickerState extends State<CameraPicker>
       newOrientation = null;
     }
     // Throttle.
-    if (newOrientation != null && lockedCaptureOrientation != newOrientation) {
-      lockedCaptureOrientation = newOrientation;
-      realDebugPrint('Locking new capture orientation: $newOrientation');
-      controller.lockCaptureOrientation(newOrientation);
-    }
+    // if (newOrientation != null && lockedCaptureOrientation != newOrientation) {
+    //   lockedCaptureOrientation = newOrientation;
+    //   realDebugPrint('Locking new capture orientation: $newOrientation');
+    //   controller.lockCaptureOrientation(newOrientation);
+    // }
+    controller.lockCaptureOrientation(lockedCaptureOrientation);
   }
 
   /// Initializes the flash modes in [validFlashModes] for each
@@ -782,8 +773,7 @@ class CameraPickerState extends State<CameraPicker>
     if (enableScaledPreview) {
       // Ignore point update when the new point is less than 8% and higher than
       // 92% of the screen's height.
-      if (position.dy < constraints.maxHeight / 12 ||
-          position.dy > constraints.maxHeight / 12 * 11) {
+      if (position.dy < constraints.maxHeight / 12 || position.dy > constraints.maxHeight / 12 * 11) {
         return;
       }
     }
@@ -814,10 +804,8 @@ class CameraPickerState extends State<CameraPicker>
         1 / constraints.maxHeight,
       );
       await Future.wait(<Future<void>>[
-        if (controller.value.exposurePointSupported)
-          controller.setExposurePoint(newPoint),
-        if (controller.value.focusPointSupported)
-          controller.setFocusPoint(newPoint),
+        if (controller.value.exposurePointSupported) controller.setExposurePoint(newPoint),
+        if (controller.value.focusPointSupported) controller.setFocusPoint(newPoint),
       ]);
     } catch (e, s) {
       handleErrorWithHandler(e, s, pickerConfig.onError);
@@ -840,9 +828,7 @@ class CameraPickerState extends State<CameraPicker>
       }
       value = roundedOffset;
     }
-    if (value == currentExposureOffset.value ||
-        value < minAvailableExposureOffset ||
-        value > maxAvailableExposureOffset) {
+    if (value == currentExposureOffset.value || value < minAvailableExposureOffset || value > maxAvailableExposureOffset) {
       return;
     }
     final previousOffsetValue = currentExposureOffset.value;
@@ -1154,9 +1140,7 @@ class CameraPickerState extends State<CameraPicker>
   }
 
   PointerMoveEventListener? onPointerMove(BoxConstraints c) {
-    if (innerController != null &&
-        enablePullToZoomInRecord &&
-        controller.value.isRecordingVideo) {
+    if (innerController != null && enablePullToZoomInRecord && controller.value.isRecordingVideo) {
       return (PointerMoveEvent e) => onShootingButtonMove(e, c);
     }
     return null;
@@ -1255,7 +1239,8 @@ class CameraPickerState extends State<CameraPicker>
             child: flashModeSwitch,
           );
         }
-        final isPortrait = v.deviceOrientation.toString().contains('portrait');
+        //todo 改为 lockedCaptureOrientation 替换 deviceOrientation 判断
+        final isPortrait = v.lockedCaptureOrientation.toString().contains('portrait');
         return Padding(
           padding: const EdgeInsets.symmetric(horizontal: 12),
           child: Flex(
@@ -1282,9 +1267,7 @@ class CameraPickerState extends State<CameraPicker>
         onPressed: () => switchCameras(),
         icon: Icon(
           switch (defaultTargetPlatform) {
-            TargetPlatform.iOS ||
-            TargetPlatform.macOS =>
-              Icons.flip_camera_ios_outlined,
+            TargetPlatform.iOS || TargetPlatform.macOS => Icons.flip_camera_ios_outlined,
             _ => Icons.flip_camera_android_outlined,
           },
           size: 24,
@@ -1348,7 +1331,7 @@ class CameraPickerState extends State<CameraPicker>
   }) {
     const fallbackSize = 150.0;
     final previewSize = controller?.value.previewSize;
-    final orientation = controller?.value.deviceOrientation ??
+    final orientation = controller?.value.lockedCaptureOrientation ??
         MediaQuery.orientationOf(context);
     final isPortrait = orientation.toString().contains('portrait');
     double effectiveSize;
@@ -1672,13 +1655,10 @@ class CameraPickerState extends State<CameraPicker>
                 duration: _kDuration,
                 opacity: isFadeOut ? .5 : 1,
                 child: Row(
-                  textDirection: shouldReverseLayout
-                      ? TextDirection.rtl
-                      : TextDirection.ltr,
+                  textDirection: shouldReverseLayout ? TextDirection.rtl : TextDirection.ltr,
                   children: <Widget>[
                     child!,
-                    if (pickerConfig.enableExposureControlOnPoint)
-                      const SizedBox(width: 2),
+                    if (pickerConfig.enableExposureControlOnPoint) const SizedBox(width: 2),
                     if (pickerConfig.enableExposureControlOnPoint)
                       SizedBox.fromSize(
                         size: Size(exposureControlWidth, lineHeight),
@@ -1695,9 +1675,7 @@ class CameraPickerState extends State<CameraPicker>
             child: CameraFocusPoint(
               key: ValueKey<Offset>(point),
               size: pointWidth,
-              color: cameraValue.exposureMode == ExposureMode.locked
-                  ? _lockedColor
-                  : theme.iconTheme.color!,
+              color: cameraValue.exposureMode == ExposureMode.locked ? _lockedColor : theme.iconTheme.color!,
             ),
           ),
         ),
@@ -1770,6 +1748,7 @@ class CameraPickerState extends State<CameraPicker>
       preview = ValueListenableBuilder<CameraValue>(
         valueListenable: controller,
         builder: (_, CameraValue value, Widget? child) {
+          print("buildCameraPreview - ValueListenableBuilder - rebuild - lockedOrientation:${value.lockedCaptureOrientation} deviceOrientation:${value.deviceOrientation}");
           final lockedOrientation = value.lockedCaptureOrientation;
           int? quarterTurns = lockedOrientation?.index;
           if (quarterTurns == null) {
@@ -1777,11 +1756,11 @@ class CameraPickerState extends State<CameraPicker>
           }
           if (value.deviceOrientation == DeviceOrientation.landscapeLeft) {
             quarterTurns--;
-          } else if (value.deviceOrientation ==
-              DeviceOrientation.landscapeRight) {
+          } else if (value.deviceOrientation == DeviceOrientation.landscapeRight) {
             quarterTurns++;
           }
-          return RotatedBox(quarterTurns: quarterTurns, child: child);
+          //todo 强制不旋转
+          return RotatedBox(quarterTurns: 0, child: child);
         },
         child: preview,
       );
@@ -1791,8 +1770,7 @@ class CameraPickerState extends State<CameraPicker>
       onPointerUp: (_) => pointers--,
       child: GestureDetector(
         onScaleStart: pickerConfig.enablePinchToZoom ? handleScaleStart : null,
-        onScaleUpdate:
-            pickerConfig.enablePinchToZoom ? handleScaleUpdate : null,
+        onScaleUpdate: pickerConfig.enablePinchToZoom ? handleScaleUpdate : null,
         // Enabled cameras switching by default if we have multiple cameras.
         onDoubleTap: cameras.length > 1 ? switchCameras : null,
         child: preview,
@@ -1800,8 +1778,7 @@ class CameraPickerState extends State<CameraPicker>
     );
 
     // Make a transformed widget if it's defined.
-    final Widget? transformedWidget =
-        pickerConfig.previewTransformBuilder?.call(
+    final Widget? transformedWidget = pickerConfig.previewTransformBuilder?.call(
       context,
       controller,
       preview,
@@ -1810,8 +1787,7 @@ class CameraPickerState extends State<CameraPicker>
       preview = Stack(
         children: <Widget>[
           preview,
-          if (pickerConfig.enableSetExposure)
-            buildExposureDetector(context, constraints),
+          if (pickerConfig.enableSetExposure) buildExposureDetector(context, constraints),
           buildFocusingPoint(
             cameraValue: cameraValue,
             constraints: constraints,
@@ -1856,6 +1832,7 @@ class CameraPickerState extends State<CameraPicker>
       valueListenable: controller,
       builder: (_, CameraValue value, Widget? w) {
         if (isInitialized?.call() ?? value.isInitialized) {
+          print("buildInitializeWrapper - ValueListenableBuilder - rebuild - lockedOrientation:${value.lockedCaptureOrientation} deviceOrientation:${value.deviceOrientation}");
           return builder(value, w);
         }
         return const SizedBox.shrink();
@@ -1875,12 +1852,8 @@ class CameraPickerState extends State<CameraPicker>
       bottom: false,
       child: Flex(
         direction: isPortrait ? Axis.vertical : Axis.horizontal,
-        textDirection: orientation == DeviceOrientation.landscapeRight
-            ? TextDirection.rtl
-            : TextDirection.ltr,
-        verticalDirection: orientation == DeviceOrientation.portraitDown
-            ? VerticalDirection.up
-            : VerticalDirection.down,
+        textDirection: orientation == DeviceOrientation.landscapeRight ? TextDirection.rtl : TextDirection.ltr,
+        verticalDirection: orientation == DeviceOrientation.portraitDown ? VerticalDirection.up : VerticalDirection.down,
         children: <Widget>[
           Semantics(
             sortKey: const OrdinalSortKey(0),
@@ -1902,13 +1875,14 @@ class CameraPickerState extends State<CameraPicker>
     );
   }
 
+  //todo 改为 lockedCaptureOrientation 替换 deviceOrientation 判断
   Widget buildBody(BuildContext context) {
     return LayoutBuilder(
       builder: (BuildContext context, BoxConstraints constraints) {
         Widget previewWidget = ExcludeSemantics(
           child: buildInitializeWrapper(
             builder: (CameraValue v, Widget? w) {
-               //为什么相机旋转了,这了会触发回调,此时v.deviceOrientation变为left横屏了
+              //为什么相机旋转了,这了会触发回调,此时v.deviceOrientation变为left横屏了
               if (enableScaledPreview) {
                 return buildCameraPreview(
                   context: context,
@@ -1922,10 +1896,10 @@ class CameraPickerState extends State<CameraPicker>
                   DeviceOrientation.portraitDown: Alignment.bottomCenter,
                   DeviceOrientation.landscapeLeft: Alignment.centerLeft,
                   DeviceOrientation.landscapeRight: Alignment.centerRight,
-                }[v.deviceOrientation]!,
+                }[v.lockedCaptureOrientation]!,
                 child: AspectRatio(
                   aspectRatio:
-                      v.deviceOrientation.toString().contains('portrait')
+                      v.lockedCaptureOrientation.toString().contains('portrait')
                           ? 1 / v.aspectRatio
                           : v.aspectRatio,
                   child: LayoutBuilder(
@@ -1973,8 +1947,7 @@ class CameraPickerState extends State<CameraPicker>
           children: <Widget>[
             previewWidget,
             if (enableScaledPreview) ...<Widget>[
-              if (pickerConfig.enableSetExposure)
-                buildExposureDetector(context, constraints),
+              if (pickerConfig.enableSetExposure) buildExposureDetector(context, constraints),
               buildInitializeWrapper(
                 builder: (CameraValue v, _) => buildFocusingPoint(
                   cameraValue: v,
@@ -1983,8 +1956,7 @@ class CameraPickerState extends State<CameraPicker>
               ),
               if (pickerConfig.foregroundBuilder != null)
                 Positioned.fill(
-                  child:
-                      pickerConfig.foregroundBuilder!(context, innerController),
+                  child: pickerConfig.foregroundBuilder!(context, innerController),
                 ),
             ],
             if (innerController == null)
@@ -1994,7 +1966,7 @@ class CameraPickerState extends State<CameraPicker>
                 builder: (CameraValue v, _) => buildForegroundBody(
                   context,
                   constraints,
-                  v.deviceOrientation,
+                  v.lockedCaptureOrientation,
                 ),
               ),
           ],
@@ -2012,9 +1984,7 @@ class CameraPickerState extends State<CameraPicker>
         quarterTurns: pickerConfig.cameraQuarterTurns,
         child: MediaQuery(
           data: mq.copyWith(
-            size: pickerConfig.cameraQuarterTurns.isOdd
-                ? mq.size.flipped
-                : mq.size,
+            size: pickerConfig.cameraQuarterTurns.isOdd ? mq.size.flipped : mq.size,
           ),
           child: body,
         ),