flutter正式发布以来,官方库和三方库也是该有的功能都有了,可以说是选择颇多,但是还是建议按照官方的来,毕竟再怎么搞,自己也不能搬起石头砸自己的脚,按照正版的永远没错。 这里我选择的是image_picker,photo,这两个库,具体使用哪个版本,可以点进去查看最新的版本号,不过如果你的androidX版本过低,会产生一些兼容问题,这个问题是所有最新的库都有可能存在的问题,由于我用的是一年前老项目,不太清楚谷歌新初始化的脚手架,有没有存在此问题,具体方法,放于另一篇文章讲解。
image_picker 用于短视频商城源码中的相机打开,虽然此库也可以选择图片,但是只能选择单张图片,至少我用的这个版本只能选一张,所有就需要再引入photo库来解决选择多张的问题。
首先声明我们需要的数据结构:
import 'package:photo/photo.dart'; import 'package:photo_manager/photo_manager.dart'; import 'package:image_picker/image_picker.dart'; class PickImageResponse { final List<String> paths; // 用于上传 final List<File> files; // 用于展示用的缩略图 PickImageResponse({this.paths, this.files}); }封装打开相机方法:
final ImagePicker picker = ImagePicker(); // 打开相机 Future<PickImageResponse> Function() openCamera = () async { final PickedFile img = await picker.getImage(source: ImageSource.camera); if (img.path == null) return PickImageResponse(); return PickImageResponse(paths: [img.path], files: [File(img.path)]); };photo 用于打开相册,选择多张图片。
// 选择相册多张图片 Future<PickImageResponse> Function(BuildContext, int) pickImageFromAlbum = (BuildContext context, int rest) async { List<AssetEntity> imgList = await PhotoPicker.pickAsset( context: context, themeColor: Color(0xff00c295), textColor: Colors.white, padding: 1.0, dividerColor: Colors.grey, disableColor: Colors.grey.shade300, itemRadio: 0.88, maxSelected: rest, provider: I18nProvider.chinese, rowCount: 3, thumbSize: 150, sortDelegate: SortDelegate.common, checkBoxBuilderDelegate: DefaultCheckBoxBuilderDelegate( activeColor: Colors.white, unselectedColor: Colors.white, checkColor: Color(0xff00c295), ), badgeDelegate: DurationBadgeDelegate(), pickType: PickType.onlyImage, ); if (imgList == null || imgList.isEmpty) return PickImageResponse(); List<String> r = []; List<File> f = []; for (var e in imgList) { var file = await e.file; f.add(file); r.add(file.absolute.path); } return PickImageResponse(paths: r, files: f); };上面是我配的一套ui,你可以根据需求进行相关修改。
由于有个bottom-sheet选择弹层,这里我就直接用了flutter自身的ios风格ui库进行了一次二次封装
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class CupertinoActionSheetOptions { final List<dynamic> items; final void Function(int) callback; final String title; final String message; CupertinoActionSheetOptions( {@required this.items, this.callback, this.title, this.message}); } // 底部普通弹出菜单 - ios风格 void Function(BuildContext, CupertinoActionSheetOptions) bottomSheet = (BuildContext context, CupertinoActionSheetOptions options) { showCupertinoModalPopup( context: context, builder: (BuildContext ctx) { return CupertinoActionSheet( cancelButton: CupertinoActionSheetAction( onPressed: () { router.back(context); }, child: Text( '取消', style: TextStyle(color: Color(0xffcdcdcd)), )), actions: options.items .map((item) => CupertinoActionSheetAction( onPressed: () { final int idx = options.items.indexOf(item); if (options.callback != null) { options.callback(idx); } router.back(context, idx); }, child: Text(item.toString()))) .toList(), ); }); return; };最后封装成统一对外的方法:
// 打开选择框 void Function(BuildContext, int, Function(PickImageResponse)) pickImageFromCameraOrAlbum = (BuildContext context, int rest, Function(PickImageResponse) callback) { bottomSheet( context, CupertinoActionSheetOptions( items: ['拍照', '相册'], callback: (int idx) async { if (idx == 0) return callback(await openCamera()); return callback(await pickImageFromAlbum(context, rest)); })); return; };选中之后缩略图的展示图下:
imgList .map( (e) => Container( height: 80.0, width: 80.0, margin: EdgeInsets.only(right: 8.0), decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(8.0)), image: DecorationImage( fit: BoxFit.cover, image: FileImage(e,), ), color: Color(0xFFF0F0F0), ) ).toList() // 或者直接使用 Image.file(file)