一、安装
-
安装插件,注意:
裁剪库需要额外配置# 相机、相册库 $ flutter pub add image_picker # 裁剪库 $ flutter pub add image_cropper -
每次修改了配置,需要
clean在get重新安装,要不然会使用编译好的缓存运行,所以避免问题,从根本解决问题:# 先清空 $ flutter clean # 再安装 $ flutter pub get # 运行 $ flutter run -
Android权限配置,文件路径android/app/src/main/AndroidManifest.xml<!-- 请求相机权限 --> <uses-permission android:name="android.permission.CAMERA"/> <!-- 请求读取存储权限(读取相册) --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <!-- 请求写入存储权限(选择和保存相册中的图片)--> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- 如果使用了访问相册,且是 Android 10(API 29)及以上版本,还需要配置 --> <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" /> -
iOS权限配置,文件路径ios/Runner/Info.plist<key>Localization native development region</key> <string>zh_CN</string> <key>NSCameraUsageDescription</key> <string>我们需要访问您的相机</string> <key>NSPhotoLibraryUsageDescription</key> <string>我们需要访问您的照片库</string>Localization native development region会使相机、相册打开后显示中文。附:# Flutter iOS 调起相机、相册显示英文,需要改成中文。
二、image_cropper 安卓问题处理
-
不需要裁剪功能,就不用看这段了。
-
image_cropper在iOS上没问题,但是在安卓上需要将compileSdk修改为35,文件路径android/app/build.gradle未来最新的版本可能不是
35,可能更高,按着报错改就行。不修改会报错:
Your project is configured to compile against Android SDK 34, but the following plugin(s) require to be compiled against a higher Android SDK version: - image_cropper compiles against Android SDK 35 Fix this issue by compiling against the highest Android SDK version (they are backward compatible). Add the following to /Users/dengzemiao/Desktop/Project/flutter/flutter-edu-app/android/app/build.gradle: android { compileSdk = 35 ... } FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':app:processDebugResources'. > A failure occurred while executing com.android.build.gradle.internal.res.LinkApplicationAndroidResourcesTask$TaskAction > Android resource linking failed com.example.testbaseproject.app-mergeDebugResources-42:/values-v35/values-v35.xml:4: error: style attribute 'android:attr/windowOptOutEdgeToEdgeEnforcement' not found. error: failed linking references. * Try: > Run with --stacktrace option to get the stack trace. > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. > Get more help at https://help.gradle.org. BUILD FAILED in 9s修改后,还不行,需要确定
Android Studio安装好了35的sdk,注意安装包支持的CPU类型,安装好了就行了。 -
nonono,再次运行,可以正常使用了,但是在拍好照片进行裁剪的还会报错,可能还会报错,一大串的,可以搜搜里面有没有com.yalantis.ucrop.UCropActivity,就是缺少了activity的申明,所以还需要配置下,文件路径android/app/src/main/AndroidManifest.xml在
application里面再加一个activity申明:<activity android:name="com.yalantis.ucrop.UCropActivity" android:theme="@style/Theme.AppCompat.Light.NoActionBar"/> -
到这里就真的
ok了,可以放心使用裁剪了,如果不需要裁剪后面这些配置可以不用配置,只要配置权限即可。
三、裁剪封装
-
使用
// 导入 import 'package:base_project/utils/camera_utils.dart'; // 使用 CustomBottomSheet.show( context: context, list: ['拍照', '打开相册'], onConfirm: (index) async { if (index == 0) { // 打开相机 await camera.showCamera( cropping: true, onChanged: (value) => { print('图片路径: $value') } ); } else { // 打开相册 await camera.showAlbum( cropping: true, onChanged: (value) => { print('图片路径: $value') } ); } }, ); -
camera_utils.dartimport 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:image_cropper/image_cropper.dart'; class CameraUtils { // 静态变量存储单例 static final CameraUtils _instance = CameraUtils._internal(); // 静态方法获取单例实例 factory CameraUtils() => _instance; // 私有构造函数,确保只能通过工厂方法获取实例 CameraUtils._internal(); // 静态的 _picker 变量,确保只会初始化一次 final ImagePicker _picker = ImagePicker(); // 打开相机 Future<void> showCamera({ bool? cropping, ValueChanged<String>? onChanged }) async { try { final XFile? file = await _picker.pickImage(source: ImageSource.camera); if (file != null) { if (cropping == true) { await _cropImage( path: file.path, onChanged: onChanged ); } else { if (onChanged != null) { onChanged(file.path); } } } else { if (onChanged != null) { onChanged(''); } } } catch (e) { if (onChanged != null) { onChanged(''); } // print('图片选择出错: $e'); } } // 打开相册 Future<void> showAlbum({ bool? cropping, ValueChanged<String>? onChanged }) async { try { final XFile? file = await _picker.pickImage(source: ImageSource.gallery); if (file != null) { if (cropping == true) { await _cropImage( path: file.path, onChanged: onChanged ); } else { if (onChanged != null) { onChanged(file.path); } } } else { if (onChanged != null) { onChanged(''); } } } catch (e) { // print('图片选择出错: $e'); if (onChanged != null) { onChanged(''); } } } // 图片裁剪方法 Future<void> _cropImage({ required String path, ValueChanged<String>? onChanged }) async { try { // 使用 image_cropper 进行裁剪 final file = await ImageCropper().cropImage( sourcePath: path, uiSettings: [ AndroidUiSettings( toolbarTitle: '裁剪图片', toolbarColor: Colors.deepOrange, toolbarWidgetColor: Colors.white, initAspectRatio: CropAspectRatioPreset.square, lockAspectRatio: false, ), IOSUiSettings( minimumAspectRatio: 1.0, aspectRatioLockEnabled: false ), ] ); // 如果裁剪成功 if (file != null && onChanged != null) { // 图片裁剪成功,返回裁剪后的图片 onChanged(file.path); } } catch (e) { // print('裁剪出错: $e'); if (onChanged != null) { onChanged(''); } } } }