前一段项目要做类似微信朋友圈的评论回复功能,要多选图片,当时在网上也找了一下,发现文章并不是太多,就把自己写的也记录一下(主要是我们的项目使用的flutter版本太低了1.17.2的,flutter2.0.1版本之上可使用images_picker
插件,一个插件满足您的需求)。
插件
dependencies:
photo:
path: ./flutter_photo #这个插件pub_dev上也不是最新的,我是把作者发布到git上的拉下来导入到项目中了
image_picker: ^0.6.7+22
为什么要用两个插件,是因为image_picker
这个插件虽然支持拍照和相册选择,但是图片只能一张一张的选择,photo
是支持图片多选的(但是这个插件好久没更新了)
废话不多说,开始上代码:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_app_image_picker/photo_picker_tool.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar:AppBar(
title:Text('PhotoSelectTest')
),
body:
Container(
padding: EdgeInsets.fromLTRB(80, 10, 30, 10),
color: Colors.red,
child:
JhPhotoPickerTool(
lfPaddingSpace: 110,
callBack: (var img) async{
print("img-------${File(img[0]).lengthSync()}------");
print(img.length);
print(img);
},
)
)
);
}
}
import 'package:flutter/material.dart';
import 'package:jxcapp/utils/image_utils.dart';
import 'package:photo/photo.dart';
import 'package:photo_manager/photo_manager.dart';
import 'dart:io';
import 'package:image_picker/image_picker.dart';
import 'package:heic_to_jpg/heic_to_jpg.dart';
const double itemSpace = 10.0;
const double space = 5.0; //上下左右间距
const double deleBtnWH = 20.0;
const Color bgColor = Colors.white;
const int maxCount = 3;// 最大选择图片数量
typedef CallBack = void Function(List imgData);
class JhPhotoPickerTool extends StatefulWidget {
final double lfPaddingSpace; //外部设置的左右间距
final CallBack callBack;
JhPhotoPickerTool({
this.lfPaddingSpace,
this.callBack,
});
@override
_JhPhotoPickerToolState createState() => _JhPhotoPickerToolState();
}
class _JhPhotoPickerToolState extends State {
List _imgData = List(); //图片list
List imgDefaultData = List(); //图片list
List imgPicked = [];
@override
void initState() {
// TODO: implement initState
super.initState();
imgDefaultData.add("selectPhoto_add"); //先添加 加号按钮 的图片
}
@override
void setState(fn) {
// TODO: implement setState
super.setState(fn);
List data = List();
data.addAll(_imgData);
// data.removeAt(_imgData.length - 1);
widget.callBack(data);
}
@override
Widget build(BuildContext context) {
var kScreenWidth = MediaQuery.of(context).size.width;
var lfPadding = widget.lfPaddingSpace == null ? 0.0 : widget.lfPaddingSpace;
var ninePictureW = (kScreenWidth - space * 2 - 2 * itemSpace - lfPadding);
var itemWH = ninePictureW / maxCount;
int columnCount = _imgData.length > 6 ? 3 : _imgData.length <= 3 ? 1 : 2;
return Container(
color: bgColor,
width: kScreenWidth - lfPadding,
height:
columnCount * itemWH + space * 2 + (columnCount - 1) * itemSpace,
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
//可以直接指定每行(列)显示多少个Item
//一行的Widget数量
crossAxisCount: 3,
crossAxisSpacing: itemSpace, //水平间距
mainAxisSpacing: itemSpace, //垂直间距
childAspectRatio: 1.0, //子Widget宽高比例
),
physics: NeverScrollableScrollPhysics(),
padding: EdgeInsets.all(space),
//GridView内边距
itemCount: _imgData.length== maxCount?_imgData.length: (_imgData.length + imgDefaultData.length),
itemBuilder: (context, index) {
if (_imgData.length == maxCount) {
return imgItem(index, setState, _imgData, imgPicked);
} else {
if (index == _imgData.length) {
return addBtn(context, setState, imgDefaultData, imgPicked);
} else {
return imgItem(index, setState, _imgData, imgPicked);
}
}
}));
}
/** 添加按钮 */
Widget addBtn(context, setState, imgData, imgPicked) {
return GestureDetector(
child: Container(
color: Color(0xffF7F7F7),
padding: EdgeInsets.all(40),
child: Image.asset(
ImageUtils.getImgPath('report/report_add_icon'),
// fit: BoxFit.cover,
),
),
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return new Container(
height: 195.0,
child: Column(
children: [
MaterialButton(
height:50,
child: Text('拍摄'),
onPressed: () async {
Navigator.pop(context);
var image = await ImagePicker.pickImage(
source: ImageSource.camera);
print(image);
if(image.absolute.path.contains('.he') || image.absolute.path.contains('.HE')){
String jpegPath = await HeicToJpg.convert(image.absolute.path);
_imgData.insert(_imgData.length, jpegPath);
}
else{
_imgData.insert(_imgData.length, image.absolute.path);
}
// _imgPicked.add(image);
setState(() {});
},
),
SizedBox(
height: 1,
child: Container(
color: Color(0xffF4F4F4),
),
),
MaterialButton(
height:50,
child: Text('从手机相册选择'),
onPressed: () async {
pickAsset(context, setState, _imgData, imgPicked);
Navigator.pop(context);
},
),
SizedBox(
height: 10,
child: Container(
color: Color(0xffF4F4F4),
),
),
MaterialButton(
height:50,
child: Text('取消'),
onPressed: () {
Navigator.pop(context);
},
),
],
),
);
},
).then((val) {
print(val);
});
},
);
}
/** 多图选择 */
void pickAsset(context, setState, imgData, imgPicked) async {
final result = await PhotoPicker.pickAsset(
context: context,
pickedAssetList: imgPicked,
maxSelected: maxCount - _imgData.length,
pickType: PickType.onlyImage);
if (result != null && result.isNotEmpty) {
for (var e in result) {
var file = await e.file;
// if (!imgData.contains(file.absolute.path)) {// 如果想避免重复选同一张图片,可以加上这个判断
if(file.absolute.path.contains('.he') || file.absolute.path.contains('.HE')){// 这个判断的意义请继续往下看
String jpegPath = await HeicToJpg.convert(file.absolute.path);
_imgData.insert(_imgData.length, jpegPath);
}
else{
_imgData.insert(_imgData.length, file.absolute.path);
}
// }
}
}
setState(() {});
}
/** 图片和删除按钮 */
Widget imgItem(index, setState, imgData, imgPicked) {
return GestureDetector(
child: Container(
color: Colors.transparent,
child: Stack(alignment: Alignment.topRight, children: [
ConstrainedBox(
child: Image.file(File(imgData[index]), fit: BoxFit.cover),
constraints: BoxConstraints.expand(),
),
GestureDetector(
child: Image.asset(
ImageUtils.getImgPath('report/report_delete'),//这是我本地的添加图片
// fit: BoxFit.cover,
),
onTap: () {
//点击删除按钮
setState(() {
_imgData.removeAt(index);
// imgPicked.removeAt(index);
});
},
)
]),
),
onTap: () {
print("点击第${index}张图片");
},
);
}
}
以上就是我的代码,可能有的朋友就问了heic_to_jpg
这个插件是干什么用的, 苹果heic格式图片不能直接在浏览器上显示,所以我们就需要借用插件转换一下格式,详细请看:
heic:https://baike.baidu.com/item/HEIC/10444257
jpg: https://baike.baidu.com/item/JPEG%E6%A0%BC%E5%BC%8F/3462770
HEIF & HEVC https://juejin.im/post/59ddc13ff265da432319f438
到这里还不算结束,安卓还有一个问题,就是系统是安卓11
及以上相册打不开,你需要修改你项目中的这个地方,上图:
这里就是去除安卓11的新特性,可以使插件正常使用。
以上就是这篇文章的全部内容了,写的不好的地方还请多多指教!