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)