flutter中用GridView撸出可拖拽,删除,上传等图片操作
import 'package:flutter/material.dart';
import 'package:n9a_crm/widgets/tip/tip.dart';
class ProductImg extends StatefulWidget {
@override
_ProductImgState createState() => _ProductImgState();
}
class _ProductImgState extends State<ProductImg> {
var _imgs = [
"http://img5.mtime.cn/mg/2020/04/02/100052.90885849.jpg",
"http://img5.mtime.cn/mg/2020/03/30/104612.95383214.jpg",
"http://img5.mtime.cn/mg/2020/04/07/092906.73796826.jpg",
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fn.sinaimg.cn%2Fsinacn12%2F0%2Fw640h960%2F20180426%2F356f-fzrwiay9756380.jpg&refer=http%3A%2F%2Fn.sinaimg.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1619680186&t=6098cb2d8c6588bdbc7d2b4f27e6f133"
];
String _movingValue; // 记录正在移动的数据
_deleImg(String value) {
setState(() {
this._imgs.remove(value);
});
}
// 生成GridView的items
List<Widget> buildItems() {
List<Widget> items = List<Widget>();
_imgs.forEach((value) {
items.add(draggableItem(value));
});
items.add(UpBtn(imgList: _imgs));
return items;
}
// 生成可拖动的item
Widget draggableItem(value) {
return Draggable(
data: value,
child: DragTarget(
builder: (context, candidateData, rejectedData) {
return baseItem(value);
},
onWillAccept: (moveData) {
print('=== onWillAccept: $moveData ==> $value');
var accept = moveData != null;
if (accept) {
exchangeItem(moveData, value, false);
}
return accept;
},
onAccept: (moveData) {
print('=== onAccept: $moveData ==> $value');
exchangeItem(moveData, value, true);
},
onLeave: (moveData) {
print('=== onLeave: $moveData ==> $value');
},
),
feedback: Container(
width: 110,
height: 110,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(5)),
child: Image.network(
value,
fit: BoxFit.cover,
))),
childWhenDragging: null,
onDragStarted: () {
print('=== onDragStarted');
setState(() {
_movingValue = value; //记录开始拖拽的数据
});
},
onDraggableCanceled: (Velocity velocity, Offset offset) {
print('=== onDraggableCanceled');
setState(() {
_movingValue = null; //清空标记进行重绘
});
},
onDragCompleted: () {
print('=== onDragCompleted');
},
);
}
// 基础展示的item 此处设置width,height对GridView 无效,主要是偷懒给feedback用
Widget baseItem(value, [bgColor]) {
if (value == _movingValue) {
return Container();
}
return Stack(
children: [
Container(
width: double.infinity,
height: double.infinity,
color: bgColor,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(5)),
child: Image.network(
value,
fit: BoxFit.cover,
))),
Positioned(
child: GestureDetector(
onTap: () => _deleImg(value),
behavior: HitTestBehavior.translucent,
child: Image.asset('assets/product/close.png'),
),
top: 0,
right: 0,
)
],
);
}
// 重新排序
void exchangeItem(moveData, toData, onAccept) {
setState(() {
var toIndex = _imgs.indexOf(toData);
_imgs.remove(moveData);
_imgs.insert(toIndex, moveData);
if (onAccept) {
_movingValue = null;
}
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Container(
alignment: Alignment.centerLeft,
margin: EdgeInsets.only(left: 15, top: 10, bottom: 10),
child: Text(
'产品图片',
style: TextStyle(color: Color(0xff888888), fontSize: 15),
),
),
Tip(text: '支持 jpg、png格式,拖动图片重新排序,默认第一张图片为主图,建议每张上传文件大小200K以内'),
Container(
margin: EdgeInsets.only(
top: 15,
left: 15,
right: 15,
),
child: GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, mainAxisSpacing: 15, crossAxisSpacing: 15, childAspectRatio: 1),
children: buildItems(),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(), //禁止滚动
),
),
],
);
}
}
//添加图片
class UpBtn extends StatefulWidget {
final imgList;
UpBtn({Key key, this.imgList}) : super(key: key);
@override
_UpBtnState createState() => _UpBtnState();
}
class _UpBtnState extends State<UpBtn> {
//选择相册照片
Future getImage() async {
var imageUrl = await ImagePicker().getImage(source: ImageSource.gallery);
setState(() {
widget.imgList.add(imageUrl);
});
print(widget.imgList);
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: getImage,
child: Container(
decoration: BoxDecoration(
color: Color(0xfff7f7f7),
borderRadius: BorderRadius.all(Radius.circular(5)),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.only(bottom: 5),
child: Image.asset(
'assets/product/addimg.png',
),
),
Text('添加图片', style: TextStyle(fontSize: 13, color: Color(0xff888888)))
],
),
),
);
}
}
//效果如下,可拖动,拿走不谢

本人小白,各位想踏入前端的,我们可以一起学习,欢迎程序员大佬的指点
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了