温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Flutter重构属性透传及函数透传如何使用

发布时间:2023-01-09 09:19:56 来源:亿速云 阅读:105 作者:iii 栏目:开发技术

这篇文章主要介绍“Flutter重构属性透传及函数透传如何使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Flutter重构属性透传及函数透传如何使用”文章能帮助大家解决问题。

    一、来源

    今天在研究 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;

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

    关于“Flutter重构属性透传及函数透传如何使用”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注亿速云行业资讯频道,小编每天都会为大家更新不同的知识点。

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI