1.输入法导致的null
--StatefulWidget
状态丢失了
- 背景:
在一个页面中有TextField
和一个Wrap
,其中Wrap
是包含了一个不定数量的List<Image> list,该页面是某个页面push进来的,传入的list可能为null
,也可能不为null
,为null
的时候在initState
创建了一个空的List,问题在于,当点击TextField
弹起输入法时,导致Wrap
中的照片全部丢失了。
如果StatefulWidget
是上一个页面创建的,输入法弹起会导致页面重建,上个页面传入的参数重置,从而导致意外发生
- 原因分析:
输入法的弹出和消失导致了StatefulWidget.didUpdateWidget
、StatefulWidget.build
两个方法的执行,其中在didUpdateWidget
时丢失了部分状态,特别时在initState
方法中初始化的状态会丢失,导致页面的build
时发生意外。 - 解决:
overridedidUpdateWidget
方法,把需要保存的状态值,重新赋值给新的Widget。
- 扩展:有可能在其他情况也会导致didUpdateWidget方法的执行,导致Widget重新创建,所有如果你的StatefulWidget中的某些状态是需要在
initState
方法中创建的,那么你就覆写didUpdateWidget
方法,从而保留你需要的值。
2.输入法弹出又自动消失?
背景
由于使用了Provider
管理状态,所有界面均为StatelessWidget
。登录界面的Form
表单设置了final GlobalKey<FormState> loginKey = GlobalKey();
,如果这个key
定义在Widget内部,当点击TextFormFiled
时弹出输入法,会导致该StatelessWidget
重构,并使得输入法自动消失。建议定义在全局变量,以避免错误发生。
//正确定义位置
final GlobalKey<FormState> loginKey = GlobalKey();
class LoginPage extends StatelessWidget {
//导致错误的写法
// final GlobalKey<FormState> loginKey = GlobalKey();
@override
Widget build(BuildContext context) {
return Form(
key:loginKey
);
}
}
3.输入法消失导致TextFormFiled
文本自动消失?
背景如2,由于输入法的弹出与消失导致
StatelessWidget
重构,所以要保证所用的TextEditingController
不发生变化。修改方法就是将TextEditingController
定义在全局或者传递进来TextEditingController
并保证在TextEditingController
重构时不变化
4.在Column中嵌套一个ListView
由于ListView的高度或者宽度是无限的,导致布局错误,从而
Widget
的丢失,黑屏或者Widget
不可见。一个解决办法就是把ListView
嵌入Expanded
.
5.run或build时卡Gradle的
可能是墙了,按照网上说的,配置Flutter SDK中的
..SdkDir\packages\flutter_tools\gradle\flutter.gradle
和工程下的../android/build.gradle
中的maven配置
// google() 改为
maven { url 'https://maven.aliyun.com/repository/google' }
// jcenter() 改为
maven { url 'https://maven.aliyun.com/repository/jcenter' }
具体url 可以查看阿里Maven
对于新配置的环境,另外一种可能是
Flutter SDK
与Android SDK version
不对应。
cmd 下执行 flutter doctor 查看'Android SDK version'
Flutter version 1.12.13+hotfix.7 要求Android 28
,首次运行时,高于该版本无错误报告并卡住,低于该版本报错
6.Flutter SDK 降级方法
7.可滚动的 ExpansionTile
Flutter原生的
ExpansionTile
,展开的是一个Column
,如果子列表项太多,则会导致溢出,且不可上下滚动。
改造,复制所有ExpansionTile
代码,修改其中的build
方法:
@override
Widget build(BuildContext context) {
final bool closed = !_isExpanded && _controller.isDismissed;
return LayoutBuilder(
builder: (c, con) {
//通过LayoutBudilder获取父布局对大小的限制
return AnimatedBuilder(
animation: _controller.view,
builder: _buildChildren,
child: closed
? null
: ConstrainedBox(
constraints: BoxConstraints(
maxWidth: con.biggest.width,
maxHeight: con.biggest.height - 58 //减掉title的高度,一般是58
),
child: ListView(
children: widget.children,
),
),
);
},
);
}