ListView的Widget被更新
在业务开发中ListView每个Cell有一个点赞功能。点赞动画由AnimationController控制,通过didUpdateWidget判断点赞值执行动画。问题在当删除未点赞状态Cell,被删除的未点赞Cell下面是点赞Cell上移,而上移点赞Cell会再执行一次动画。
@override
void didUpdateWidget(ItemCell oldWidget) {
if (oldWidget.value != value) {
if (_controller != null) {
if (value) {
_controller?.duration = Duration(seconds: 2);
_controller?.forward();
} else {
_controller?.value = 0;
_controller?.stop(canceled: true);
}
}
}
super.didUpdateWidget(oldWidget);
}
从代码层面上看只有widget的value值发生改变了才会执行动画。debug后发现oldWidget的value并不是该Cell原来的值,而是被删除Cell的值。由此可知ListView的Cell应该存在复用问题。
解决方案
- ListView每个itemCell增加Key保证唯一性。
🚀Demo案例🚀
TextField在iOS平台输入中文
当TextField设置字数限制时,在iOS上会出现输入拼音字母会限制中文生成。比如限制输入字数是4个,当你想输入中文”你好“,无法输入完整拼音字符”nihao“。
解决方案
- 简单处理,不设置字数输入限制将字数限制交给业务方实现。
- 暂无完美解决方案;一个开源库解决方案是将iOS输入框字符判断通过原生插件实现:CustomTextField。
正确使用MethodChannel
在业务开发中遇到一个沙雕问题,插件回调结果报错异常。看了下插件代码才知道原来的同学以result.error返回了结果。
业务错误信息应该也是以result.success返回才对,业务异常也需要返回携带错误信息的回参。由于历史遗留问题最终是在Flutter层做try-catch保护。
result.error并不会返回和success一样的Map<String,String>对象而是一个Flutter层异常。只能通过try-catch获取到。
try{
Map map = await FlutterAppPlugin.testChanelFail();
Scaffold.of(context).showSnackBar(
SnackBar(content: Text("testChannel ${map.toString()}"))
);
}catch(e){
Scaffold.of(context).showSnackBar(
SnackBar(content: Text("testChannel error ${e.toString()} "))
);
}
解决方案
1.通过try-catch方式在Flutter层捕获异常来知悉原生层面失败异常。
2.原生层统一返回result.success在回参字段中判断是否失败。 🚀Demo案例🚀
TextField获取/失去焦点以及软键盘获取
业务开发中遇到的输入框一些奇葩问题:
- 让输入框失去焦点:FocusScope.of(context).requestFocus(new FocusNode());
- 主动唤起软键盘: SystemChannels.textInput.invokeMethod('TextInput.show');
- 获取输入框光标位置:textEditingController.selection中的textSelection.start和textSelection.end。当输入框失去焦点时start和end会变成-1。这时最好通过一个变量记住原来的start和end。对于自定义emoji或是@用户等需求时可在原光标位置插入数据。
非循环Gif的播放问题
已知Gif有loop属性,有播放次数限制的gif会在播放次数到达之后停止。但重新加载图片应该是可以重新播放。但Flutter组件Image存在不再播放的情况,猜测是图片缓存导致重新加载后不再播放。
在页面dispose方法清缓存重新进页面gif可重新播放,由此可判断是图片缓存导致。
PaintingBinding.instance.imageCache.clear();
在image_stream.dart的_handleAppFrame找到Gif播放限制,当循环次数completedCycles超过
编码器次数_codec!.repetitionCount则不在绘制下一帧图像。
由此可知在image_provider.dart的resolveStreamForKey缓存中取出已有MultiFrameImageStreamCompleter在播放循环次数超过后取出时gif就不会再播放。
解决方案
- 简单解决办法执行PaintingBinding.instance.imageCache.clear();在不需要时暴力清缓存,但会误伤所有缓存。
- 重写image_provider.dart方法resolveStreamForKey逻辑,在缓存中取出ImageStreamCompleter对_framesEmitted参数置为0。