欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

Flutter重构属性透传及函数透传使用示例,

来源: 开发者 投稿于  被查看 12380 次 评论:25

Flutter重构属性透传及函数透传使用示例,


目录
  • 一、来源
    • 函数透传
  • 二、 WechatPhotoPicker 使用示例
    • 二、 WechatPhotoPicker 组件源码
      • 总结

        一、来源

        今天在研究 flutter 相册库 wechat_assets_picker 遇到一个问题:(我需要在第三方库基础上封装一个组件,供项目内部调用,组件内封装一些公共逻辑。)但是 AssetPicker.pickAssets 的属性太多了,一个个传递实在太麻烦,就想是否有 vue 中那种数据透传的解决方法呢(已知 flutter 中目前不支持这种属性透传)?苦苦思索5分钟之后,灵光一闪:

        函数透传

        /// pickAssets 方法源码:
        static Future<List<AssetEntity>?> pickAssets(
          BuildContext context, {
          List<AssetEntity>? selectedAssets,
          int maxAssets = 9,
          int pageSize = 80,
          int gridThumbSize = Constants.defaultGridThumbSize,
          int pathThumbSize = 80,
          int gridCount = 4,
          RequestType requestType = RequestType.image,
          List<int>? previewThumbSize,
          SpecialPickerType? specialPickerType,
          Color? themeColor,
          ThemeData? pickerTheme,
          SortPathDelegate<AssetPathEntity>? sortPathDelegate,
          AssetsPickerTextDelegate? textDelegate,
          FilterOptionGroup? filterOptions,
          WidgetBuilder? specialItemBuilder,
          IndicatorBuilder? loadingIndicatorBuilder,
          SpecialItemPosition specialItemPosition = SpecialItemPosition.none,
          bool allowSpecialItemWhenEmpty = false,
          AssetSelectPredicate<AssetEntity>? selectPredicate,
          bool? shouldRevertGrid,
          bool useRootNavigator = true,
          Curve routeCurve = Curves.easeIn,
          Duration routeDuration = const Duration(milliseconds: 300),
        }) async {
        ...
        

        二、 WechatPhotoPicker 使用示例

        class WechatPhotoPickerDemo extends StatefulWidget {
          WechatPhotoPickerDemo({ Key? key, this.title}) : super(key: key);
          final String? title;
          @override
          _WechatPhotoPickerDemoState createState() => _WechatPhotoPickerDemoState();
        }
        class _WechatPhotoPickerDemoState extends State<WechatPhotoPickerDemo> {
          int maxCount = 9;
          List<AssetEntity> entitys = [];
          GlobalKey<WechatPhotoPickerState> _globalKey = GlobalKey();
          @override
          Widget build(BuildContext context) {
            return Scaffold(
                appBar: AppBar(
                  title: Text(widget.title ?? "$widget"),
                  actions: ['选择',].map((e) => TextButton(
                    child: Text(e,
                      style: TextStyle(color: Colors.white),
                    ),
                    onPressed: onPicker,
                  )).toList(),
                ),
                body: Column(
                  children: [
                    WechatPhotoPicker(
                      key: _globalKey,
                      selectedAssets: entitys,
                      onChanged: (List<AssetEntity> selectedAssets) {
                        print("selectedAssets: ${selectedAssets.length}");
                      },
                      onPicker: () => AssetPicker.pickAssets(
                          context,
                          maxAssets: 8,
                          selectedAssets: entitys,
                        ),
                    )
                  ],
                )
            );
          }
          onPicker() async {
            _globalKey.currentState?.onPicker();
            print(entitys.length);
          }
        }
        

        二、 WechatPhotoPicker 组件源码

        /// 基于 wechat_assets_picker 的图片选择组件
        class WechatPhotoPicker extends StatefulWidget {
          WechatPhotoPicker({
            Key? key,
            this.selectedAssets = const [],
            this.maxCount = 9,
            this.rowCount = 3,
            this.spacing = 10,
            this.decoration,
            this.addBuilder,
            required this.onChanged,
            this.onPicker,
          }) : super(key: key);
          /// 媒体对象数组
          List<AssetEntity> selectedAssets;
          /// 最大个数
          int maxCount;
          /// 每行元素个数
          int rowCount;
          /// 元素间距
          double spacing;
          /// 元素修饰器
          BoxDecoration? decoration;
          /// 添加图片
          Widget Function(BuildContext context, double itemWidth)? addBuilder;
          /// 确认选择回调函数
          void Function(List<AssetEntity> selectedAssets) onChanged;
          /// 解决flutter数据无法透传的问题(透传 AssetPicker.pickAssets 方法)
          Future<List<AssetEntity>?> Function()? onPicker;
          @override
          WechatPhotoPickerState createState() => WechatPhotoPickerState();
        }
        class WechatPhotoPickerState extends State<WechatPhotoPicker> {
          @override
          Widget build(BuildContext context) {
            return photoSection(
              selectedAssets: widget.selectedAssets,
              maxCount: widget.maxCount,
              rowCount: widget.rowCount,
              spacing: widget.spacing,
            );
          }
          photoSection({
            List<AssetEntity> selectedAssets = const [],
            int maxCount = 9,
            int rowCount = 3,
            double spacing = 10,
          }) {
            return LayoutBuilder(
                builder: (BuildContext context, BoxConstraints constraints){
                  double itemWidth = ((constraints.maxWidth - spacing * (rowCount - 1))/rowCount).truncateToDouble();
                  // print("itemWidth: $itemWidth");
                  return Wrap(
                      spacing: spacing,
                      runSpacing: spacing,
                      children: [
                        ...selectedAssets.map((e) => Container(
                          clipBehavior: Clip.antiAlias,
                          decoration: widget.decoration ?? BoxDecoration(
                            // border: Border.all(width: 2),
                            borderRadius: BorderRadius.all(Radius.circular(4)),
                          ),
                          child: FadeInImage(
                            width: itemWidth,
                            height: itemWidth,
                            placeholder: AssetImage('images/img_placeholder.png'),
                            image: AssetEntityImageProvider(e, isOriginal: false),
                            fit: BoxFit.cover,
                          ),
                        )).toList(),
                        if (selectedAssets.length < maxCount)
                          InkWell(
                            onTap: () {
                              onPicker();
                            },
                            child: Container(
                              width: itemWidth,
                              height: itemWidth,
                              decoration: BoxDecoration(
                                color: Colors.black.withOpacity(0.1),
                                // border: Border.all(width: 1),
                                borderRadius: BorderRadius.all(Radius.circular(4)),
                              ),
                              child: widget.addBuilder != null ? widget.addBuilder!(context, itemWidth) : Icon(
                                Icons.add, 
                                size: itemWidth/3, 
                                color: Colors.black.withOpacity(0.3),
                              ),
                            ),
                          )
                      ]
                  );
                }
            );
          }
          onPicker() async {
            List<AssetEntity>? result = widget.onPicker != null ? await widget.onPicker!() :
            await AssetPicker.pickAssets(
              context,
              maxAssets: widget.maxCount,
              selectedAssets: widget.selectedAssets,
            );
            widget.selectedAssets = result ?? [];
            widget.onChanged(widget.selectedAssets);
            setState(() { });
          }
        }
        

        总结

        1、onPicker 参数需要和调用方法搭配使用,即实现了函数透传,函数里的参数直接暴露给外部使用者,做二次定制开发;如果默认参数(可以适量添加)能够满足通用需求,则无需使用 onPicker 可选参数;

          onPicker: () => AssetPicker.pickAssets(
              context,
              maxAssets: 8,
              selectedAssets: entitys,
            ),
        
            List<AssetEntity>? result = widget.onPicker != null ? await widget.onPicker!() :
            await AssetPicker.pickAssets(
              context,
              maxAssets: widget.maxCount,
              selectedAssets: widget.selectedAssets,
            );
        

        2、WechatPhotoPickerState,没有使用下换线(私有)实现是为了向外部暴露 State, 可以通过 GlobalKey 获取 State 实例对象,进而调用一些封装方法;达到更高的代码复用;

        声明 GlobalKey:

         GlobalKey:<WechatPhotoPickerState> _globalKey = GlobalKey();
        

        调用 State 方法:

        _globalKey.currentState?.onPicker();
        

        3、所有自定义组件原则上都要支持 key 属性,才是一个完整的组件 Widget;

        无论是移动原生、前端 h5 或者 flutter 跨平台,各种数据透传的思想是相近,在一端取得突破之后,其他端基本都是平移实现,这些可以减少代码量又不损失功能,而且维护性和扩展性更优的实现方式就是代码重构的本质。

        以上就是Flutter 重构属性透传及函数透传使用示例的详细内容,更多关于Flutter 重构属性函数透传的资料请关注3672js教程其它相关文章!

        您可能感兴趣的文章:
        • flutter中的资源和图片加载示例详解
        • flutter的导航和路由使用示例详解
        • Flutter实现固定header底部滑动页效果示例
        • 大型项目里Flutter测试应用实例集成测试深度使用详解
        • Flutter Widget移动UI框架使用Material和密匙Key实战
        • Flutter交互并使用小工具管理其状态widget的state详解
        • Flutter项目手势运用及单独指针消歧问题解决方案
        • Flutter框架解决盒约束widget和assets里加载资产技术

        用户评论