1.在使用Textfield中遇到的问题
flutter中的onchange方法和oc中的textField:(UITextField *)textField shouldChangeCharactersInRange:方法的不同
onchange方法中调用刷新方法的时候,会导致循环进入方法中,光标乱闪
///对当前的TextField下的controller监听去刷视图
_controller.addListener(() {
setState(() {});
});
TextField(
controller: _controller,
focusNode: _focusNode,
textInputAction: TextInputAction.search,
style: TextStyle(fontSize: 17, color: Colours.text),
maxLines: 1,
cursorColor: Colours.app_main,
textCapitalization: TextCapitalization.characters,
inputFormatters: [
LengthLimitingTextInputFormatter(21),
FilteringTextInputFormatter.allow(RegExp('[a-z0-9A-Z ]')),
],
decoration: InputDecoration(
border: InputBorder.none,
hintText: '请输入VIN码或点击图片上传',
///这个右侧一键清除的按钮,不随着文字是否存在变动
suffixIcon: _controller.text.isNotEmpty
? IconButton(
icon: Icon(IconFont.guanbi,
size: 15, color: Color(0x66000000)),
onPressed: () => _controller.clear())
: null),
onChanged: (value) {
///这边onchangge的方法,和oc中的输入监听不同,oc中的监听是实时监听,输入前,这个是后
var formateValue = _viewModel.getFormateVinCode(value);
if (formateValue.length % 4 == 0) {
var _newtext = _controller.text + ' ';
_controller.value = TextEditingValue(
text: _newtext,
selection: TextSelection.fromPosition(TextPosition(
affinity: TextAffinity.downstream,
offset: _newtext.length)));
}
},
onSubmitted: (value) {
do some thing...
},
),
2.wrap空间包含row问题
Warp流控件中child中包含row控件的时候,要使用MainAxisSize.min的
wrap流式布局的时候,里面使用了row进行自适应的时候,要采用上述的属性,不然wrap中每行都会充满,
官方注释:
/// Minimize the amount of free space along the main axis, subject to the
/// incoming layout constraints.
///
/// If the incoming layout constraints have a large enough
/// [BoxConstraints.minWidth] or [BoxConstraints.minHeight], there might still
/// be a non-zero amount of free space.
///
/// If the incoming layout constraints are unbounded, and any children have a
/// non-zero [FlexParentData.flex] and a [FlexFit.tight] fit (as applied by
/// [Expanded]), the [RenderFlex] will assert, because there would be infinite
/// remaining free space and boxes cannot be given infinite size.
//最小化沿主轴的空闲空间,取决于
//输入布局约束。
///如果传入的布局约束有足够大
/ / / [BoxConstraints。minWidth]或[BoxConstraints。可能还会有
///是一个非零的空闲空间。
///如果传入的布局约束是无界的,并且任何子元素都有
/ / /非零(FlexParentData。和一个[FlexFit. flex]。配合(如应用于
/// [Expanded]), [RenderFlex]将断言,因为会有无限
///剩余的空闲空间和盒子不能被赋予无限的大小。
wrap中每个只有在边界的时候有个强力约束,每个item没有强约束,所以导致在wrap中使用row控件的时候,row控件会沾满整个wrap控件的一行,充满了item的导致,设置min使其最小化空间约束,根据自控件的内容来进行最小布局约束。
3.Flutter 标签字体下沉Bug
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 3,vertical: 1),
decoration: BoxDecoration(
color: widget.tagBackGroundColor,
borderRadius: BorderRadius.circular(3)),
child: Text(
widget.tagString,
textAlign: TextAlign.center,
style: TextStyle(color: widget.tagTextColor, fontSize: 10),
),
);
}
测试阶段发现,标签在不同的机器上,标签的样式都不一样。如果什么都不设置就会导致字体偏下。基于之前的React开发经验,基本可以确定是字体行高导致的问题。但是Flutter Text组件没有直接设置行高的地方,只需Text设置strutStyle,指定fontSize和外层style设置的字体一致、设置合适的height即可,height值为14/10的值。
child: Text(
widget.tagString,
textAlign: TextAlign.center,
strutStyle: StrutStyle(fontSize: 10,height: 1.4),
style: TextStyle(color: widget.tagTextColor, fontSize: 10),
),
为什么height设置为1.4,因为默认fontSize为14,标签使用字体值为10,height默认放大1.4倍。
/// The size of text (in logical pixels) to use when obtaining metrics from the font.
///
/// The [fontSize] is used to get the base set of metrics that are then used to calculated
/// the metrics of strut. The height and leading are expressed as a multiple of
/// [fontSize].
///
/// The default fontSize is 14 logical pixels.
final double? fontSize;
4.Flutter鸿蒙字体被截问题
视觉反馈这个页面的时间字体被截,但是我的机器上都是好的,测试机器也是好的,然后我让视觉把测试机拿过来现场调试,发现是鸿蒙系统。后来慢慢排查,找到了解决方案,只需给包裹Text的外层容器设置一层白色背景即可。
5.Flutter长数字字母省略的显示问题
期望展示效果,单号位置,超出宽度末尾...省略展示
通常做法对Text设置overflow:
overflow: TextOverflow.ellipsis
但以上属性的缺陷是,当遇到长数字,长字母时,会被整体省略:
利用零宽空格字符处理这个问题:
///插入零宽空格字符
String breakWord(String word) {
if (word == null || word.isEmpty) {
return word;
}
var breakWord = ' ';
word.runes.forEach((element) {
breakWord += String.fromCharCode(element);
breakWord += '\u200B';
});
return breakWord;
}
text: breakWord(value),
另一种写法
text: value.replaceAll('', '\u200B')
两种写法,在实际展示样式上,视觉显示宽度略有差异。
此外,第二种写法,用replaceAll在处理包含emoji的字符串时会出现not utf-16的问题。
看情况使用以上两种方式处理即可。
6.Flutter中设置图片宽高失效问题
如下代码,发现设置图片宽高无效
Container(
width: 30,
height: 30,
decoration: BoxDecoration(
color: ThemeColors.halfTranslucent,
borderRadius: BorderRadius.circular(15)),
child: LoadAssetImage("ic_back",width: 24,height: 24,)
)
解决方案:在LoadAssetImage前再包一层即可生效
Container(
width: 30,
height: 30,
decoration: BoxDecoration(
color: ThemeColors.halfTranslucent,
borderRadius: BorderRadius.circular(15)),
child: Center(
child: LoadAssetImage("ic_back",width: 24,height: 24,),
),
)
7.Flutter中double精度问题
背景:由于 Dart 使用了和js一样的 IEEE 754 双精度标准进行存储,所以存在和JS一样的精度计算问题
解决方案:采用decimal这个三方库解决
#解决精度问题
decimal: 0.3.5
refundAmount =
"${Decimal.parse("$amountDesc") * Decimal.parse("$refundNumber")}";
8.键盘遮挡问题
1.存在在输入文字的时候,若不选择选择文字预览文字情况下,直接点击拍照,会导致在拍照界面出现键盘,无法进行收起
2.移动开单2.0侧筛界面,当选择确认按钮的时候,一直点击,会导致pop页面多次的情况,导致界面进行多次返回的情况。
原因:
1.该情况,在做收起键盘的操作的时候,未点击预览文字时,直接跳转下个界面的时候,会导致键盘没有完全收起来,同时下面收起键盘的方法的时候,虽然收起了键盘,但是光标仍然存在。
SystemChannels.textInput.invokeMethod('TextInput.hide');
2.侧边页面出现的时候,一直点击确定按钮的时候,会调多次pop方法,会导致关闭抽屉栏页面后,页面还会存在调用一个pop的问题,导致会产生返回上一个界面的问题。
解决
1.使用该方法,收起键盘的同时收起光标,在空白,滑动,点击弹框的时候均收起键盘
FocusScope.of(context).requestFocus(FocusNode());
2.在点击确定的时候,增加标志位,在页面销毁之前,只会调用一次。
防抖解决方法:
新增到公共库里,支持自定义防抖时间,默认一秒防抖
import 'dart:async';
///按钮防抖,milliseconds防抖时间,默认1秒
Function debounce(Function func, {int milliseconds = 1000}) {
Timer timer;
Function target = () {
if (timer?.isActive ?? false) {
timer?.cancel();
}
timer = Timer(Duration(milliseconds: milliseconds), () {
func?.call();
});
};
return target;
}
使用
child: GestureDetector(
onTap: debounce(() {
print('点击了');
},milliseconds:1500),
),
9.flutter时间格式转换问题
//正常情况下时间格式转字符
var selectedTimeStr =
selectedMonth ?? DateFormat('yyyy-MM').format(DateTime.now());
//可以将时间戳转成对应的字符串
var selectedMonth = '2022-06',
//将字符串转时间戳的时候,正常使用parse方法
var parseTime = DateTime.parse(selectedMonth);
//但是parse只能针对标准格式转化的,比如2022-06这个就无法转,只能转下面标准格式,
//否则会报FormatException错
/// * "2012-02-27"
/// * "2012-02-27 13:27:00"
/// * "2012-02-27 13:27:00.123456789z"
/// * "2012-02-27 13:27:00,123456789z"
/// * "20120227 13:27:00"
/// * "20120227T132700"
/// * "20120227"
/// * "+20120227"
/// * "2012-02-27T14Z"
/// * "2012-02-27T14+00:00"
/// * "-123450101 00:00:00 Z"
: in the year -12345.
/// * "2002-02-27T14:00:00-0500"
: Same as "2002-02-27T19:00:00Z"
//使用下面可以解决报错问题,但是无法正确解析,返回的是now的时间格式
var tryParseTime = DateTime.tryParse(selectedMonth) ?? DateTime.now();
//使用下面的可以正常解析
var parseStrictTime = DateFormat('yyyy-MM').parseStrict(selectedMonth);
//parseStrict可以解析任意格式保持统一的,下面的可以解析成2022-01-01 0000000时间
selectedMonth = '2022-';
parseStrictTime = DateFormat('yyyy-').parseStrict(selectedMonth);