
开篇寄语
flutter从相册启用视频,在不同的系统中需要开启不同的权限,同时只需要安装一个名为image_picker的依赖库,之后简单的几行代码,就可以实现这个功能了,如果想播放视频,则需要引入之前介绍的一个依赖库,名字叫做video_player,之后就可以播放视频,以及录制视频了。
前情提要
内容详情
以下内容是更改lib下的main.dart文件内容,删掉里面的内容,复制粘贴代码,开启调试就可以出现了。
首先是安装image_picker这个依赖库,在terminal中输入以下命令:
flutter pub add image_picker
回车后就开始安装了,安装完成后,则需要开启iOS和Android的使用权限。
iOS文件夹中找到ios/Runner/Info.plist,添加以下代码:
<key>NSPhotoLibraryUsageDescription</key> <string>Allow this app to access your photos</string> <key>NSCameraUsageDescription</key> <string>Allow access to camera to capture photos</string> <key>NSMicrophoneUsageDescription</key> <string>Allow access to microphone</string>
如下图所示:

该依赖库在0.81版本后,在Android4.3版本后就无需另外添加访问权限了。
做好以上准备后,就可以在main.dart文件放入以下代码了:
// ignore_for_file: prefer_const_constructors, use_key_in_widget_constructors import 'dart:async'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:video_player/video_player.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Video Picker Demo', home: MyHomePage(title: 'Video Picker Example'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({Key? key, this.title}) : super(key: key); final String? title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { VideoPlayerController? _controller; VideoPlayerController? _toBeDisposed; String? _retrieveDataError; final ImagePicker _picker = ImagePicker(); 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(); await controller.setLooping(true); await controller.play(); setState(() {}); } } void _onImageButtonPressed( ImageSource source, ) async { if (_controller != null) { await _controller!.setVolume(0.0); } final XFile? file = await _picker.pickVideo( source: source, maxDuration: const Duration(seconds: 10)); await _playVideo(file); } @override void deactivate() { if (_controller != null) { _controller!.setVolume(0.0); _controller!.pause(); } super.deactivate(); } @override void dispose() { _disposeVideoController(); 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 _handlePreview() { return _previewVideo(); } Future<void> retrieveLostData() async { final LostDataResponse response = await _picker.retrieveLostData(); if (response.isEmpty) { return; } if (response.file != null) { if (response.type == RetrieveType.video) { await _playVideo(response.file); } } else { _retrieveDataError = response.exception!.code; } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title!), ), body: Center( child: !kIsWeb ? 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>[ Padding( padding: const EdgeInsets.only(top: 16.0), child: FloatingActionButton( backgroundColor: Colors.red, onPressed: () { _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: () { _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; } } class AspectRatioVideo extends StatefulWidget { const AspectRatioVideo(this.controller); final VideoPlayerController? controller; @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 void initState() { super.initState(); controller!.addListener(_onVideoControllerUpdate); } @override void dispose() { controller!.removeListener(_onVideoControllerUpdate); super.dispose(); } @override Widget build(BuildContext context) { if (initialized) { return Center( child: AspectRatio( aspectRatio: controller!.value.aspectRatio, child: VideoPlayer(controller!), ), ); } else { return Container(); } } }
生成效果如下图所示:

选择视频后,就能够播放了,如下图所示:

如果在真机上实际操作,还可以选择下面从照相机录制视频后读取视频播放。
- 我的微信
- 微信扫一扫加好友
-
- 我的微信公众号
- 扫描关注公众号
-