Flutter图片选择插件image_picker_linux的使用
Flutter图片选择插件image_picker_linux的使用
image_picker_linux
是一个为 Linux 系统实现的图片选择插件。它允许你在 Flutter 应用中通过摄像头或图库来选择图片或视频。
限制
ImageSource.camera
除非设置了cameraDelegate
,否则不被支持。pickImage()
方法中的参数maxWidth
、maxHeight
和imageQuality
当前不被支持。pickVideo()
方法中的参数maxDuration
当前不被支持。
使用
导入包
这个包是被官方推荐使用的,因此你可以直接导入并使用 file_selector
包。这会自动包含在你的应用中,所以你不需要在 pubspec.yaml
文件中添加它。
如果你要导入此包以直接使用其 API,则需要将其添加到 pubspec.yaml
文件中:
dependencies:
flutter:
sdk: flutter
image_picker_platform_interface: ^0.8.0
file_selector: ^0.9.0
示例代码
以下是一个完整的示例代码,展示了如何在 Flutter 中使用 image_picker_linux
插件来选择图片或视频。
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
import 'package:mime/mime.dart';
import 'package:video_player/video_player.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Image Picker Demo',
home: MyHomePage(title: 'Image Picker Example'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, this.title});
final String? title;
[@override](/user/override)
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<XFile>? _mediaFileList;
// This must be called from within a setState() callback
void _setImageFileListFromFile(XFile? value) {
_mediaFileList = value == null ? null : <XFile>[value];
}
dynamic _pickImageError;
bool _isVideo = false;
VideoPlayerController? _controller;
VideoPlayerController? _toBeDisposed;
String? _retrieveDataError;
final ImagePickerPlatform _picker = ImagePickerPlatform.instance;
final TextEditingController maxWidthController = TextEditingController();
final TextEditingController maxHeightController = TextEditingController();
final TextEditingController qualityController = TextEditingController();
Future<void> _playVideo(XFile? file) async {
if (file != null && mounted) {
await _disposeVideoController();
final VideoPlayerController controller = VideoPlayerController.file(File(file.path));
_controller = controller;
await controller.setVolume(1.0);
await controller.initialize();
await controller.setLooping(true);
await controller.play();
setState(() {});
}
}
Future<void> _onImageButtonPressed(
ImageSource source, {
required BuildContext context,
bool isMultiImage = false,
bool isMedia = false,
}) async {
if (_controller != null) {
await _controller!.setVolume(0.0);
}
if (context.mounted) {
if (_isVideo) {
final XFile? file = await _picker.getVideo(
source: source, maxDuration: const Duration(seconds: 10));
await _playVideo(file);
} else if (isMultiImage) {
await _displayPickImageDialog(context,
(double? maxWidth, double? maxHeight, int? quality) async {
try {
final List<XFile> pickedFileList = isMedia
? await _picker.getMedia(
options: MediaOptions(
allowMultiple: isMultiImage,
imageOptions: ImageOptions(
maxWidth: maxWidth,
maxHeight: maxHeight,
imageQuality: quality,
)),
)
: await _picker.getMultiImageWithOptions(
options: MultiImagePickerOptions(
imageOptions: ImageOptions(
maxWidth: maxWidth,
maxHeight: maxHeight,
imageQuality: quality,
),
),
);
setState(() {
_mediaFileList = pickedFileList;
});
} catch (e) {
setState(() {
_pickImageError = e;
});
}
});
} else if (isMedia) {
await _displayPickImageDialog(context,
(double? maxWidth, double? maxHeight, int? quality) async {
try {
final List<XFile> pickedFileList = <XFile>[];
final XFile? media = _firstOrNull(await _picker.getMedia(
options: MediaOptions(
allowMultiple: isMultiImage,
imageOptions: ImageOptions(
maxWidth: maxWidth,
maxHeight: maxHeight,
imageQuality: quality,
)),
));
if (media != null) {
pickedFileList.add(media);
setState(() {
_mediaFileList = pickedFileList;
});
}
} catch (e) {
setState(() => _pickImageError = e);
}
});
} else {
await _displayPickImageDialog(context,
(double? maxWidth, double? maxHeight, int? quality) async {
try {
final XFile? pickedFile = await _picker.getImageFromSource(
source: source,
options: ImagePickerOptions(
maxWidth: maxWidth,
maxHeight: maxHeight,
imageQuality: quality,
),
);
setState(() {
_setImageFileListFromFile(pickedFile);
});
} catch (e) {
setState(() {
_pickImageError = e;
});
}
});
}
}
}
[@override](/user/override)
void deactivate() {
if (_controller != null) {
_controller!.setVolume(0.0);
_controller!.pause();
}
super.deactivate();
}
[@override](/user/override)
void dispose() {
_disposeVideoController();
maxWidthController.dispose();
maxHeightController.dispose();
qualityController.dispose();
super.dispose();
}
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 (_mediaFileList != null) {
return Semantics(
label: 'image_picker_example_picked_images',
child: ListView.builder(
key: UniqueKey(),
itemBuilder: (BuildContext context, int index) {
final String? mime = lookupMimeType(_mediaFileList![index].path);
return Semantics(
label: 'image_picker_example_picked_image',
child: mime == null || mime.startsWith('image/')
? Image.file(
File(_mediaFileList![index].path),
errorBuilder: (BuildContext context, Object error,
StackTrace? stackTrace) {
return const Center(
child: Text('This image type is not supported'));
},
)
: _buildInlineVideoPlayer(index),
);
},
itemCount: _mediaFileList!.length,
),
);
} 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 _buildInlineVideoPlayer(int index) {
final VideoPlayerController controller = VideoPlayerController.file(File(_mediaFileList![index].path));
const double volume = 1.0;
controller.setVolume(volume);
controller.initialize();
controller.setLooping(true);
controller.play();
return Center(child: AspectRatioVideo(controller));
}
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: _handlePreview(),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Semantics(
label: 'image_picker_example_from_gallery',
child: FloatingActionButton(
key: const Key('image_picker_example_from_gallery'),
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,
isMedia: true,
);
},
heroTag: 'multipleMedia',
tooltip: 'Pick Multiple Media from gallery',
child: const Icon(Icons.photo_library),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
onPressed: () {
_isVideo = false;
_onImageButtonPressed(
ImageSource.gallery,
context: context,
isMedia: true,
);
},
heroTag: 'media',
tooltip: 'Pick Single Media from gallery',
child: const Icon(Icons.photo_library),
),
),
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),
),
),
if (_picker.supportsImageSource(ImageSource.camera))
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, context: context);
},
heroTag: 'video0',
tooltip: 'Pick Video from gallery',
child: const Icon(Icons.video_library),
),
),
if (_picker.supportsImageSource(ImageSource.camera))
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
backgroundColor: Colors.red,
onPressed: () {
_isVideo = true;
_onImageButtonPressed(ImageSource.camera, context: context);
},
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> _displayPickImageDialog(
BuildContext context, OnPickImageCallback onPick) async {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Add optional parameters'),
content: Column(
children: <Widget>[
TextField(
controller: maxWidthController,
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
decoration: const InputDecoration(
hintText: 'Enter maxWidth if desired'),
),
TextField(
controller: maxHeightController,
keyboardType:
const TextInputType.numberWithOptions(decimal: true),
decoration: const InputDecoration(
hintText: 'Enter maxHeight if desired'),
),
TextField(
controller: qualityController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
hintText: 'Enter quality if desired'),
),
],
),
actions: <Widget>[
TextButton(
child: const Text('CANCEL'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('PICK'),
onPressed: () {
final double? width = maxWidthController.text.isNotEmpty
? double.parse(maxWidthController.text)
: null;
final double? height = maxHeightController.text.isNotEmpty
? double.parse(maxHeightController.text)
: null;
final int? quality = qualityController.text.isNotEmpty
? int.parse(qualityController.text)
: null;
onPick(width, height, quality);
Navigator.of(context).pop();
}),
],
);
});
}
}
typedef OnPickImageCallback = void Function(
double? maxWidth, double? maxHeight, int? quality);
class AspectRatioVideo extends StatefulWidget {
const AspectRatioVideo(this.controller, {super.key});
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();
}
}
}
T? _firstOrNull<T>(List<T> list) {
return list.isEmpty ? null : list.first;
}
更多关于Flutter图片选择插件image_picker_linux的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter图片选择插件image_picker_linux的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中为Linux平台使用image_picker_linux
插件来选择图片的示例代码。
首先,确保你的Flutter环境已经设置好,并且你的项目已经创建。如果还没有创建项目,可以使用以下命令创建一个新的Flutter项目:
flutter create my_flutter_app
然后,导航到你的项目目录:
cd my_flutter_app
1. 添加依赖
在pubspec.yaml
文件中添加image_picker
及其Linux平台的依赖:
dependencies:
flutter:
sdk: flutter
image_picker: ^latest_version # 使用最新版本,请替换为实际最新版本号
dependency_overrides:
image_picker_linux: ^latest_version # 如果需要覆盖为特定版本,请替换为实际最新版本号
然后运行flutter pub get
来安装依赖。
2. 配置Linux平台
在linux
目录下,打开CMakeLists.txt
文件,并添加对image_picker_linux
插件的支持。通常,这个步骤对于使用image_picker
插件来说是自动处理的,但如果你遇到构建问题,可能需要手动确认或添加相关配置。不过,大多数情况下,只需确保依赖正确安装即可。
3. 使用插件
现在,你可以在你的Dart代码中使用image_picker
插件来选择图片。以下是一个简单的示例:
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Image Picker Demo'),
),
body: Center(
child: MyHomePage(),
),
),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ImagePicker _picker = ImagePicker();
File? _imageFile;
Future<void> _pickImage(ImageSource source) async {
final XFile? image = await _picker.pickImage(source: source);
if (image != null) {
final File imageFile = File(image.path);
// 如果你需要在Linux上显示图片,可以使用一个Image.file小部件
setState(() {
_imageFile = imageFile;
});
}
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextButton(
onPressed: () => _pickImage(ImageSource.gallery),
child: Text('Pick Image from Gallery'),
),
SizedBox(height: 20),
TextButton(
onPressed: () => _pickImage(ImageSource.camera),
child: Text('Pick Image from Camera'),
),
SizedBox(height: 20),
if (_imageFile != null)
Image.file(
_imageFile!,
width: 300,
height: 300,
fit: BoxFit.cover,
),
],
);
}
}
4. 运行应用
确保你的开发环境中已经安装了Flutter SDK和必要的依赖,然后运行以下命令来构建并运行你的应用:
flutter run -d linux
这将启动你的Flutter应用在Linux平台上,并允许你选择图片。
请注意,由于Linux平台的一些限制,特别是与文件选择和相机访问相关的权限问题,你可能需要在运行应用之前或运行时授予相应的权限。如果遇到权限问题,请检查你的Linux发行版和桌面环境的文档,了解如何授予Flutter应用必要的访问权限。