在码农的世界里,优美的应用体验,来源于程序员对细节的处理以及自我要求的境界,年轻人也是忙忙碌碌的码农中一员,每天、每周,都会留下一些脚印,就是这些创作的内容,有一种执着,就是不知为什么,如果你迷茫,不妨来瞅瞅码农的轨迹。
如果你有兴趣 你可以关注一下公众号 biglead 来获取最新的学习资料。
先来看看本文章实现的效果
直接来看代码吧
首先是启动函数
main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
home: DemoSelectImageWidgetPage(),
));
}
然后是这个首页面,核心代码就是 SelectPhotoWidget 这个组件
class DemoSelectImageWidgetPage extends StatefulWidget {
@override
_DemoSelectImageWidgetPageState createState() =>
_DemoSelectImageWidgetPageState();
}
class _DemoSelectImageWidgetPageState extends State<DemoSelectImageWidgetPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey,
appBar: AppBar(title: Text("图片选择组件")),
body: Center(
child: Container(
padding: EdgeInsets.all(12),
child: SelectPhotoWidget(
header: Text(
"请选择照片",
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 18),
),
tips: "请注意 最多选择5张图片",
imageSelectAction: (List<String> list) {
print("实时选择回调${list.toString()}");
},
maxSelect: 6,
imageList: [],
),
),
),
);
}
}
将核心功能封装在了 SelectPhotoWidget 组件中,大家可以直接复制使用
class SelectPhotoWidget extends StatefulWidget {
final Function(List<String>) imageSelectAction;
final Widget header;
final String tips;
final List<String> imageList;
final int maxSelect;
final ImageType imageType;
const SelectPhotoWidget(
{Key key,
this.header,
this.tips,
this.imageList,
this.imageType = ImageType.asset,
this.imageSelectAction,
this.maxSelect = 5})
: super(key: key);
@override
State<StatefulWidget> createState() {
return _SelectPhotoWidgetState();
}
}
class _SelectPhotoWidgetState extends State<SelectPhotoWidget>
with WidgetsBindingObserver {
bool _isSelect = false;
@override
void initState() {
super.initState();
if (widget.imageList != null) {
if (widget.imageList.length <= widget.maxSelect) {
_imageList = widget.imageList;
} else {
_imageList = widget.imageList.sublist(0, widget.maxSelect);
}
}
WidgetsBinding.instance.addObserver(this);
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.inactive:
break;
case AppLifecycleState.resumed:
break;
case AppLifecycleState.paused:
break;
case AppLifecycleState.detached:
break;
}
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(12)),
child: Container(
color: Color(0xffFFFFFF),
width: double.infinity,
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
buildHeaderWidget(),
buildTipsWidget(),
buildGridView(),
SizedBox(
height: 10,
),
],
),
),
);
}
buildHeaderWidget() {
return widget.header != null ? widget.header : Container();
}
buildTipsWidget() {
if (widget.tips == null || widget.tips.length == 0) {
return Container();
}
return Container(
padding: EdgeInsets.only(top: 10, bottom: 16),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(12)),
child: Container(
padding: EdgeInsets.only(left: 10, right: 10, top: 6, bottom: 6),
color: Color(0xffFFF1F1),
child: Text(
"${widget.tips}",
style: TextStyle(
color: Color(0xffBD2F2F),
fontSize: 14,
),
),
),
),
);
}
List<String> _imageList = [];
buildGridView() {
return Container(
child: GridView.builder(
padding: EdgeInsets.only(top: 8, bottom: 8),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: getSelectCount(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
mainAxisSpacing: 1.0,
crossAxisSpacing: 1.0,
childAspectRatio: 1.0),
itemBuilder: (BuildContext context, int index) {
if (index == _imageList.length) {
if (_isSelect) {
return Center(child: Text("..."));
}
return Container(
margin: EdgeInsets.only(top: 10),
child: IconButton(
icon: Icon(Icons.add),
onPressed: () {
onSelectImageFunction();
},
),
color: Color(0xFFF1F1F2),
);
}
String imageUrl = _imageList[index];
return Container(
child: Stack(
children: [
Positioned.fill(
top: 10,
right: 10,
child: GestureDetector(
onTap: () {
},
child: Container(
padding: EdgeInsets.all(1),
child: buildImageWidget(imageUrl),
color: Colors.grey[200],
),
),
),
Positioned(
top: 0,
right: 0,
child: GestureDetector(
onTap: () {
onDeleteImageFunction(index);
},
child: ClipOval(
child: Container(
padding: EdgeInsets.all(2),
color: Colors.red,
child: Icon(
Icons.close,
color: Colors.white,
size: 14,
),
),
),
),
),
],
),
);
},
),
);
}
Widget buildImageWidget(String image) {
if (widget.imageType == ImageType.net) {
return Image.network(
image,
fit: BoxFit.fitWidth,
);
} else if (widget.imageType == ImageType.asset) {
return Image.asset(
image,
fit: BoxFit.fitWidth,
);
}
return Image.file(
File(image),
fit: BoxFit.fitWidth,
);
}
getSelectCount() {
if (_imageList.length >= widget.maxSelect) {
return widget.maxSelect;
}
return _imageList.length + 1;
}
void onDeleteImageFunction(int index) {
_imageList.removeAt(index);
setState(() {});
widget.imageSelectAction(_imageList);
}
void onSelectImageFunction() async {
_isSelect = true;
setState(() {});
String localImageUrl = "assets/images/sp03.png";
await Future.delayed(Duration(milliseconds: 1000));
_isSelect = false;
if (localImageUrl.length > 0) {
_imageList.add(localImageUrl);
setState(() {});
widget.imageSelectAction(_imageList);
}
}
}
|