1、空字符占位(\u3000 \u0020)使用
body: Container(
width: double.infinity,
height: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
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(),
)
],
)
],
),
),
效果如下:
从结果可知,\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 = [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 {
const factory NetworkImage(String url, { double scale, Map headers }) = network_image.NetworkImage;
...
}
NetworkImage是一个抽象类,为什么可以实例化?我们注意到NetworkImage的构造方法是一个工厂构造方法,它其实实例化的是它的子类,如下:
_network_image_io.dart
import 'image_provider.dart' as image_provider;
class NetworkImage extends image_provider.ImageProvider 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
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 json) {
doubleValue = json['DoubleValue'];
}
Map toJson() {
final Map data = new Map();
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 json) {
doubleValue = json['DoubleValue'];
}
Map toJson() {
final Map data = new Map();
data['DoubleValue'] = this.doubleValue;
return data;
}
}
注意:
- 展示时用doubleValue.toString()
- double类型的数据用toString()可能会出现小数点位数不符合要求的,需要将toString()换成toStringAsFixed(小数点位数)