Flutter图片选择插件sparrow_image_picker的使用
Flutter图片选择插件sparrow_image_picker的使用
安装
首先,在pubspec.yaml
文件中添加sparro_image_picker
作为依赖项。
iOS
该插件需要iOS 9.0或更高版本。从版本0.8.1开始,iOS实现使用PHPicker来选择(多个)图片。在iOS 14或更高版本的iOS模拟器上,无法选择HEIC格式的图片。这是一个已知问题。请在真实设备上测试,或者使用非HEIC格式的图片,直到Apple解决此问题。
在Info.plist
文件中添加以下键:
NSPhotoLibraryUsageDescription
- 描述你的应用为什么需要访问照片库。NSCameraUsageDescription
- 描述你的应用为什么需要访问相机。NSMicrophoneUsageDescription
- 如果你的应用打算录制视频,则需要描述你的应用为什么需要访问麦克风。
Android
从版本0.8.1开始,Android实现支持在Android 4.3或更高版本上选择(多个)图片。无需额外配置,插件应能直接工作。
注意:使用相机拍摄的图片和视频会保存到应用的本地缓存中,并且应被视为临时文件。如果你需要永久存储所选的图片,请将其移动到更持久的位置。
示例
以下是使用sparrow_image_picker
选择图片和视频的基本示例:
import 'package:flutter/material.dart';
import 'package:sparrow_image_picker/sparrow_image_picker.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Image Picker Demo',
home: MyHomePage(title: 'Image Picker Example'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, this.title}) : super(key: key);
final String? title;
[@override](/user/override)
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<XFile>? _imageFileList;
set _imageFile(XFile? value) {
_imageFileList = value == null ? null : [value];
}
dynamic _pickImageError;
bool isVideo = false;
VideoPlayerController? _controller;
VideoPlayerController? _toBeDisposed;
String? _retrieveDataError;
final ImagePicker _picker = ImagePicker();
void _onImageButtonPressed(ImageSource source, {BuildContext? context, bool isMultiImage = false}) async {
if (_controller != null) {
await _controller!.setVolume(0.0);
}
if (isVideo) {
final XFile? file = await _picker.pickVideo(source: source, maxDuration: const Duration(seconds: 10));
print("file=${file?.path}");
await _playVideo(file);
} else if (isMultiImage) {
final List<XFile>? pickedFileList = await _picker.pickMultiImage(count: 3);
setState(() {
_imageFileList = pickedFileList;
pickedFileList?.forEach((element) {
print("${element.path}");
print("${element.name}");
});
});
} else {
final XFile? pickedFile = await _picker.pickImage(source: source);
setState(() {
_imageFile = pickedFile;
print("_imageFile=${pickedFile?.path}");
});
}
}
Future<void> _playVideo(XFile? file) async {
if (file != null && mounted) {
await _disposeVideoController();
late VideoPlayerController controller;
if (kIsWeb) {
controller = VideoPlayerController.network(file.path);
} else {
controller = VideoPlayerController.file(File(file.path));
}
_controller = controller;
final double volume = kIsWeb ? 0.0 : 1.0;
await controller.setVolume(volume);
await controller.initialize().then((value) {
print("initialize...");
});
await controller.setLooping(true);
await controller.play();
setState(() {});
}
}
Future<void> _disposeVideoController() async {
if (_toBeDisposed != null) {
await _toBeDisposed!.dispose();
}
_toBeDisposed = _controller;
_controller = null;
}
Widget _previewVideo() {
final Text? retrieveError = _getRetrieveErrorWidget();
if (retrieveError != null) {
return retrieveError;
}
if (_controller == null) {
return const Text(
'You have not yet picked a video',
textAlign: TextAlign.center,
);
}
return Padding(
padding: const EdgeInsets.all(10.0),
child: AspectRatioVideo(_controller),
);
}
Widget _previewImages() {
final Text? retrieveError = _getRetrieveErrorWidget();
if (retrieveError != null) {
return retrieveError;
}
if (_imageFileList != null) {
return Semantics(
child: ListView.builder(
key: UniqueKey(),
itemBuilder: (context, index) {
return Semantics(
label: 'image_picker_example_picked_image',
child: kIsWeb
? Image.network(_imageFileList![index].path)
: Image.file(File(_imageFileList![index].path)),
);
},
itemCount: _imageFileList!.length,
),
label: 'image_picker_example_picked_images');
} else if (_pickImageError != null) {
return Text(
'Pick image error: $_pickImageError',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}
Widget _handlePreview() {
if (isVideo) {
return _previewVideo();
} else {
return _previewImages();
}
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title!),
),
body: Center(
child: !kIsWeb && defaultTargetPlatform == TargetPlatform.android
? FutureBuilder<void>(
future: retrieveLostData(),
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
case ConnectionState.done:
return _handlePreview();
default:
if (snapshot.hasError) {
return Text(
'Pick image/video error: ${snapshot.error}}',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}
},
)
: _handlePreview(),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Semantics(
label: 'image_picker_example_from_gallery',
child: FloatingActionButton(
onPressed: () {
isVideo = false;
_onImageButtonPressed(ImageSource.gallery, context: context);
},
heroTag: 'image0',
tooltip: 'Pick Image from gallery',
child: const Icon(Icons.photo),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
onPressed: () {
isVideo = false;
_onImageButtonPressed(
ImageSource.gallery,
context: context,
isMultiImage: true,
);
},
heroTag: 'image1',
tooltip: 'Pick Multiple Image from gallery',
child: const Icon(Icons.photo_library),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
onPressed: () {
isVideo = false;
_onImageButtonPressed(ImageSource.camera, context: context);
},
heroTag: 'image2',
tooltip: 'Take a Photo',
child: const Icon(Icons.camera_alt),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
backgroundColor: Colors.red,
onPressed: () {
isVideo = true;
_onImageButtonPressed(ImageSource.gallery);
},
heroTag: 'video0',
tooltip: 'Pick Video from gallery',
child: const Icon(Icons.video_library),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
backgroundColor: Colors.red,
onPressed: () {
isVideo = true;
_onImageButtonPressed(ImageSource.camera);
},
heroTag: 'video1',
tooltip: 'Take a Video',
child: const Icon(Icons.videocam),
),
),
],
),
);
}
Text? _getRetrieveErrorWidget() {
if (_retrieveDataError != null) {
final Text result = Text(_retrieveDataError!);
_retrieveDataError = null;
return result;
}
return null;
}
Future<void> retrieveLostData() async {
final LostDataResponse response = await _picker.retrieveLostData();
if (response.isEmpty) {
return;
}
if (response.file != null) {
if (response.type == RetrieveType.video) {
isVideo = true;
await _playVideo(response.file);
} else {
isVideo = false;
setState(() {
_imageFile = response.file;
_imageFileList = response.files;
});
}
} else {
_retrieveDataError = response.exception!.code;
}
}
}
typedef void OnPickImageCallback(double? maxWidth, double? maxHeight, int? quality);
class AspectRatioVideo extends StatefulWidget {
AspectRatioVideo(this.controller);
final VideoPlayerController? controller;
[@override](/user/override)
AspectRatioVideoState createState() => AspectRatioVideoState();
}
class AspectRatioVideoState extends State<AspectRatioVideo> {
VideoPlayerController? get controller => widget.controller;
bool initialized = false;
void _onVideoControllerUpdate() {
if (!mounted) {
return;
}
if (initialized != controller!.value.isInitialized) {
initialized = controller!.value.isInitialized;
setState(() {});
}
}
[@override](/user/override)
void initState() {
super.initState();
controller!.addListener(_onVideoControllerUpdate);
}
[@override](/user/override)
void dispose() {
controller!.removeListener(_onVideoControllerUpdate);
super.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) {
if (initialized) {
return Center(
child: AspectRatio(
aspectRatio: controller!.value.aspectRatio,
child: VideoPlayer(controller!),
),
);
} else {
return Container();
}
}
}
更多关于Flutter图片选择插件sparrow_image_picker的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter图片选择插件sparrow_image_picker的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
sparrow_image_picker
是一个用于 Flutter 的图片选择插件,它可以帮助开发者在应用中方便地从相册或相机中选择图片。以下是如何使用 sparrow_image_picker
插件的基本步骤:
1. 添加依赖
首先,在 pubspec.yaml
文件中添加 sparrow_image_picker
依赖:
dependencies:
flutter:
sdk: flutter
sparrow_image_picker: ^1.0.0 # 请使用最新版本
然后运行 flutter pub get
来安装依赖。
2. 导入插件
在你的 Dart 文件中导入 sparrow_image_picker
:
import 'package:sparrow_image_picker/sparrow_image_picker.dart';
3. 使用插件选择图片
从相册选择图片
你可以使用 pickImage
方法从相册中选择图片:
Future<void> pickImageFromGallery() async {
final imagePicker = SparrowImagePicker();
final pickedFile = await imagePicker.pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
// 处理选中的图片
print('Image path: ${pickedFile.path}');
} else {
print('No image selected.');
}
}
从相机拍摄图片
你也可以使用 pickImage
方法从相机拍摄图片:
Future<void> takePhoto() async {
final imagePicker = SparrowImagePicker();
final pickedFile = await imagePicker.pickImage(source: ImageSource.camera);
if (pickedFile != null) {
// 处理拍摄的图片
print('Image path: ${pickedFile.path}');
} else {
print('No image taken.');
}
}
4. 显示选中的图片
你可以使用 Image.file
来显示选中的图片:
Image.file(File(pickedFile.path))
5. 处理权限
在使用相机或访问相册时,可能需要处理权限问题。确保在 AndroidManifest.xml
和 Info.plist
文件中添加相应的权限声明。
Android
在 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"/>
iOS
在 Info.plist
中添加以下权限:
<key>NSCameraUsageDescription</key>
<string>需要相机权限来拍摄照片</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问相册以选择照片</string>
6. 完整示例
以下是一个完整的示例,展示如何使用 sparrow_image_picker
从相册或相机中选择图片并显示:
import 'package:flutter/material.dart';
import 'package:sparrow_image_picker/sparrow_image_picker.dart';
import 'dart:io';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: ImagePickerExample(),
);
}
}
class ImagePickerExample extends StatefulWidget {
[@override](/user/override)
_ImagePickerExampleState createState() => _ImagePickerExampleState();
}
class _ImagePickerExampleState extends State<ImagePickerExample> {
File? _image;
Future<void> pickImageFromGallery() async {
final imagePicker = SparrowImagePicker();
final pickedFile = await imagePicker.pickImage(source: ImageSource.gallery);
setState(() {
if (pickedFile != null) {
_image = File(pickedFile.path);
} else {
print('No image selected.');
}
});
}
Future<void> takePhoto() async {
final imagePicker = SparrowImagePicker();
final pickedFile = await imagePicker.pickImage(source: ImageSource.camera);
setState(() {
if (pickedFile != null) {
_image = File(pickedFile.path);
} else {
print('No image taken.');
}
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Image Picker Example'),
),
body: Center(
child: _image == null
? Text('No image selected.')
: Image.file(_image!),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: pickImageFromGallery,
tooltip: 'Pick Image',
child: Icon(Icons.photo_library),
),
SizedBox(height: 10),
FloatingActionButton(
onPressed: takePhoto,
tooltip: 'Take Photo',
child: Icon(Icons.camera_alt),
),
],
),
);
}
}