美文网首页Flutter
Flutter 疑难杂症(二)

Flutter 疑难杂症(二)

作者: HawkFlying | 来源:发表于2020-11-06 10:43 被阅读0次

    1、空字符占位(\u3000 \u0020)使用

    body: Container(
            width: double.infinity,
            height: double.infinity,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Text('a\u0020b\u0020cdefg'),
                Text('abcdefgh'),
                Text('三\u0020\u0020字\u0020\u0020字'),
                Text('四字字字'),
                Text('二\u3000\u3000字'),
                Row(
                  children: [
                    Text('三\u0020\u0020字\u0020\u0020字'),
                    Expanded(
                      child: SizedBox(),
                    )
                  ],
                )
              ],
            ),
          ),
    

    效果如下:


    image.png

    从结果可知,\u3000相当于占用一个中文字符,\u0020相当于占用1/4个中文字符,我们可以通过\u3000或\u0020来对齐表单左边文案,注意:字体样式要一致才有效;

    2、数组、列表等自带查找匹配方法

    iterator.dart

      /**
       * Returns the first element that satisfies the given predicate [test].
       *
       * Iterates through elements and returns the first to satisfy [test].
       *
       * If no element satisfies [test], the result of invoking the [orElse]
       * function is returned.
       * If [orElse] is omitted, it defaults to throwing a [StateError].
       */
      E firstWhere(bool test(E element), {E orElse()}) {
        for (E element in this) {
          if (test(element)) return element;
        }
        if (orElse != null) return orElse();
        throw IterableElementError.noElement();
      }
    
      /**
       * Returns the last element that satisfies the given predicate [test].
       *
       * An iterable that can access its elements directly may check its
       * elements in any order (for example a list starts by checking the
       * last element and then moves towards the start of the list).
       * The default implementation iterates elements in iteration order,
       * checks `test(element)` for each,
       * and finally returns that last one that matched.
       *
       * If no element satisfies [test], the result of invoking the [orElse]
       * function is returned.
       * If [orElse] is omitted, it defaults to throwing a [StateError].
       */
      E lastWhere(bool test(E element), {E orElse()}) {
        E result;
        bool foundMatching = false;
        for (E element in this) {
          if (test(element)) {
            result = element;
            foundMatching = true;
          }
        }
        if (foundMatching) return result;
        if (orElse != null) return orElse();
        throw IterableElementError.noElement();
      }
    
      /**
       * Returns the single element that satisfies [test].
       *
       * Checks elements to see if `test(element)` returns true.
       * If exactly one element satisfies [test], that element is returned.
       * If more than one matching element is found, throws [StateError].
       * If no matching element is found, returns the result of [orElse].
       * If [orElse] is omitted, it defaults to throwing a [StateError].
       */
      E singleWhere(bool test(E element), {E orElse()}) {
        E result;
        bool foundMatching = false;
        for (E element in this) {
          if (test(element)) {
            if (foundMatching) {
              throw IterableElementError.tooMany();
            }
            result = element;
            foundMatching = true;
          }
        }
        if (foundMatching) return result;
        if (orElse != null) return orElse();
        throw IterableElementError.noElement();
      }
    

    方法说明:
    firstWhere主要是用于筛选顺序第一个符合条件的元素,可能存在多个符合条件元素;
    lastWhere主要是用于筛选顺序最后一个符合条件的元素,可能存在多个符合条件元素;
    singleWhere主要是用于筛选顺序唯一一个符合条件的元素;

    参数说明:
    bool test(E element) :查找条件匹配方法,传子元素,匹配返回true;
    E orElse():查找不到时,执行的方法,一般返回null;
    返回值:返回匹配的子元素或orElse的返回值,一般通过自定义orElse中的返回值来判断是否查找到匹配条件的元素;

    使用例子:

       var numbers = <int>[0, 3, 1, 2, 7, 12, 2, 4];
       //注意: 如果没有找到,执行orElse代码块,可返回一个指定的默认值-1
       print(numbers.firstWhere((num) => num == 5, orElse: () => -1)); 
       //注意: 如果没有找到,执行orElse代码块,可返回一个指定的默认值-1
       print(numbers.lastWhere((num) => num == 2, orElse: () => -1)); 
       //注意: 如果没有找到,执行orElse代码块,可返回一个指定的默认值, 
       //前提是集合中只有一个符合条件的元素, 否则就会抛出异常
       print(numbers.singleWhere((num) => num == 4, orElse: () => -1));
    

    使用坑:

    • E orElse()虽然是一个可选参数,但如果找不到匹配的,会直接抛出异常,所以orElse参数必须实现;

    • singleWhere慎用,因为singleWhere必须集合中只有一个符合条件的元素, 否则就会抛出异常;同时,在查找条件要求不高时,推荐使用firstWhere,因为firstWhere查找到就返回结果,而singleWhere需要所有元素都要查找才结束,firstWhere效率更高;

    3、按条件引入库

    语法:

    import <文件> if(<条件>) <文件>  as <别名>
    

    例子:

    import '_network_image_io.dart'
      if (dart.library.html) '_network_image_web.dart' as network_image;
    

    说明:
    条件参数:一般为不同平台(android/ios/桌面/web)加载的不同的处理程序(我支持您编写此库);
    使用场景:不同平台(android/ios/桌面/web)兼容开发;

    4、factory工厂构造方法

    以NetworkImage为例:

    Image(
            image: NetworkImage(imgUrl), 
    

    一般NetworkImage使用如上,看下NetworkImage源码,如下:
    image_provider.dart

    import '_network_image_io.dart'
      if (dart.library.html) '_network_image_web.dart' as network_image;
    
    abstract class NetworkImage extends ImageProvider<NetworkImage> {
     
      const factory NetworkImage(String url, { double scale, Map<String, String> headers }) = network_image.NetworkImage;
      ...
     
    }
    

    NetworkImage是一个抽象类,为什么可以实例化?我们注意到NetworkImage的构造方法是一个工厂构造方法,它其实实例化的是它的子类,如下:
    _network_image_io.dart

    import 'image_provider.dart' as image_provider;
    
    class NetworkImage extends image_provider.ImageProvider<image_provider.NetworkImage> implements image_provider.NetworkImage {
     
      const NetworkImage(this.url, { this.scale = 1.0, this.headers });
      ...
    

    _network_image_web.dart

    import 'image_provider.dart' as image_provider;
    class NetworkImage
        extends image_provider.ImageProvider<image_provider.NetworkImage>
        implements image_provider.NetworkImage {
    
      const NetworkImage(this.url, {this.scale = 1.0, this.headers});
      ...
    

    上面两个分别是对应移动和web平台NetworkImage的实现类,也就是NetworkImage的子类,并且外部不可访问;
    上面的代码比较绕,需要细心看,再理解下factory就很容易懂了

    工厂构造方法:

    • 使用 factory 关键字来定义构造方法;
    • 构造方法返回对象;
    • 构造方法可能从缓存中获取一个实例并返回,或者 返回一个子类型的实例;

    5、网络请求数据解析坑

    class TestModel {
      double doubleValue;
    
      TestModel({this.doubleValue});
    
      TestModel.fromJson(Map<String, dynamic> json) {
        doubleValue = json['DoubleValue'];
      }
    
      Map<String, dynamic> toJson() {
        final Map<String, dynamic> data = new Map<String, dynamic>();
        data['DoubleValue'] = this.doubleValue;
        return data;
      }
    }
    

    一般我们用xx.fromJson的方法来解析网络请求数据,如果后台数据doubleValue返回0,就会报type 'int' is not a subtype of type ‘double'的错误

    解决:
    将doubleValue定义为dynamic类型,如下:

    class TestModel {
      dynamic doubleValue;
    
      TestModel({this.doubleValue});
    
      TestModel.fromJson(Map<String, dynamic> json) {
        doubleValue = json['DoubleValue'];
      }
    
      Map<String, dynamic> toJson() {
        final Map<String, dynamic> data = new Map<String, dynamic>();
        data['DoubleValue'] = this.doubleValue;
        return data;
      }
    }
    

    注意:

    • 展示时用doubleValue.toString()
    • double类型的数据用toString()可能会出现小数点位数不符合要求的,需要将toString()换成toStringAsFixed(小数点位数)

    相关文章

      网友评论

        本文标题:Flutter 疑难杂症(二)

        本文链接:https://www.haomeiwen.com/subject/ctxtbktx.html