Flutter 图片选择器 SelectPhotoWidget

Posted 早起的年轻人

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter 图片选择器 SelectPhotoWidget相关的知识,希望对你有一定的参考价值。

在码农的世界里,优美的应用体验,来源于程序员对细节的处理以及自我要求的境界,年轻人也是忙忙碌碌的码农中一员,每天、每周,都会留下一些脚印,就是这些创作的内容,有一种执着,就是不知为什么,如果你迷茫,不妨来瞅瞅码农的轨迹。

如果你有兴趣 你可以关注一下公众号 biglead 来获取最新的学习资料。


先来看看本文章实现的效果

在这里插入图片描述

直接来看代码吧

首先是启动函数

main() {
  runApp(MaterialApp(
    //不显示 debug标签
    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;

  ///为true 时显示使用网络图片
  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:
        // APP结束时调用
        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(),
        //SliverGridDelegateWithFixedCrossAxisCount 构建一个横轴固定数量Widget
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            //横轴元素个数
            crossAxisCount: 4,
            //主轴间距
            mainAxisSpacing: 1.0,
            //从轴间距
            crossAxisSpacing: 1.0,
            //子组件宽高长度比例
            childAspectRatio: 1.0),
        itemBuilder: (BuildContext context, int index) {
          //Widget Function(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);
    }
  }
}

以上是关于Flutter 图片选择器 SelectPhotoWidget的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 学习 之 图片的选择裁切保存

如何从图像选择器中裁剪图像?

Flutter Web - 使用电话选择图像

Flutter 表单构建器包图像选择器 Firestore Flutter

Flutter:圆形颜色选择器(包:flutter_colorpicker)

Flutter 中的 iOS 风格的选择器控件