我正在参加「掘金·启航计划」
以下问题属于个人开发中遇到的问题及解决方案,部分是根据项目原因提出的解决办法,可能并不适用于所有人,如有问题,可及时沟通,共同成长。
1、设置启动页防止白屏问题
android需要在文件下修改luanch_background.xml文件,注意drawable和drawable-v21文件夹的区别
ios 需要在ios原生工程下xcode创建luanchScreen,使用storyboard生成跟闪屏页相同的页面
flutter 部分最好重新做一个相同的闪屏页面,注意页面的适配问题,否则会出现从原生页面过来后图标跳动的问题
2、需要在应用启动时判断是否登录状态跳转不同的页面?
因为在android文件夹下修改了启动页,这里又要在dart里面判断是否登录状态,所以需要在dart这边又要重新弄一个启动页,才能加以判断,所以这里会有两个启动页,目前还没有其他方案
3、启动页需要图片全屏显示
有三种解决方式:我使用第三种方式解决
1、通过 ConstrainedBox 的 constraints 属性设置图片充满全屏
ConstrainedBox(
constraints: BoxConstraints.expand(), // 设置延伸自适应屏幕
child: Image.asset(
"assets/images/xxx.png",
fit: BoxFit.cover,
),
)
2、使用Container包裹设置宽高为屏幕的宽高
Container(
width: MediaQuery.of(context).size.width, // 屏幕宽度
height: MediaQuery.of(context).size.height, // 屏幕高度
child: Image.asset(
"assets/images/xxx.png",
fit: BoxFit.cover,
),
)
3、如果使用了层级组件Stack,则可以这样设置
Stack(
children: [
Positioned.fill(
child: Image.asset(
"assets/images/xxx.png",
fit: BoxFit.cover,
),
),
],
)
4、TextField去掉默认的下划线
可以设置decoration的属性的border属性为InputBorder.none即可去掉下划线
TextField(
decoration: InputDecoration(
border: InputBorder.none,
),
)
5、TextField设置maxlength会在右下角显示计数问题
TextField(
decoration: InputDecoration(
//maxLength: 6 //不设置
//使用该方式限制输入长度
inputFormatters: [LengthLimitingTextInputFormatter(6)],
),
)
6、textField在row或colunm中时不设置宽高会显示有误,需要再套一层container设置宽高即可
7、webView中的url需要经过Future处理后再加载,加载的地址不正确:webView加载的是处理之前的url???
目前的解决方案是提前处理url拼接相关参数
8、SingleChildScrollView和ListView、GridView等控件嵌套使用
需要在子控件(ListView或GridView)中添加一下属性:不滚动子控件
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
9、GridView使用时需要添加childAspectRatio(宽高比参数)意义在哪??
这是flutter使用GridView必须添加参数,可以根据设计的宽高来写比列,注意适配问题
10、http接口请求报错问题
url请求的地址为http地址,需要在原生项目中添加允许http请求
11、在getX生成的页面中使用TabController?
因为getX生成的页面是stl无状态页面,如果需要使用tabController,就需要用一个stf将该页面包裹起来使用
12、两个Text文字无法对齐
试着将两个text的行高设置成一致,根据实际情况处理,也可以参考我之前的文章《flutter中 文字对齐方案》
Text(
style:TextStyle(
height: 1.1
)
)
13、TextField在ios上双击或者长按显示灰屏
需要在runapp中设置多语言适配
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
ChineseCupertinoLocalizations.delegate, // 自定义的delegate
DefaultCupertinoLocalizations.delegate, // 目前只包含英文
],
supportedLocales: const [
Locale('zh', 'CN'),
Locale('zh', 'Hans'), // China
Locale('zh', ''), // China
Locale('en', 'US'),
],
14、Text在Container中文字不居中显示
需要设置Text的strutStyle
Text(
button2,
strutStyle: StrutStyle(
fontSize: 13.sp,
leading: 0,
// 1.1更居中
forceStrutHeight: true, // 关键属性 强制改为文字高度
),
style: TextStyle(
color: MyColors.colord9000000,
fontSize: 14.sp,
fontWeight: FontWeight.bold),
),
15、ListView和GiridView会默认带padding(top:8),去掉paddding即可 padding(top:0)
16、Flutter中Timer.periodic在后台会暂停问题
目前发现Timer.periodic在安卓中是不会有任何问题,但在ios的release模式中会有问题,所以为了统一处理需要在倒计时控件中监听app的前后台状态,且计算用户在后台经过了多长时间,部分代码如下
class _CountDownWidgetState extends State<CountDownWidget> with WidgetsBindingObserver{
var _timer;
int endTime = 0;
int inTime = 0;//进来的时间
int outTime = 0;//退出的时间
@override
void initState() {
WidgetsBinding.instance?.addObserver(this);
endTime = widget.validTime;
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
if(mounted){
setState(() {
if(endTime < 1){
if (widget.isFinish != null) {
widget.isFinish!(true);
}
timer.cancel();
}else{
endTime -= 1;
}
});
}
});
super.initState();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch(state){
case AppLifecycleState.inactive://不活跃
//进入后台先走inactive
print("不活跃状态");
break;
case AppLifecycleState.resumed://应用程序可见,前台
//刚进入页面不走这里,再次进来会走这里
inTime = DateTime.now().millisecondsSinceEpoch;
print("前台:$inTime");
var lastTime = inTime - outTime;//用户进入后台的时间
print("用户进入后台一共:$lastTime 毫秒");
if(mounted){
setState(() {
var surplusTime = endTime - lastTime ~/ 1000;
print("进入前台重新计算时间:$endTime , $surplusTime");
if(surplusTime < 1){
endTime = 0;
//直接调用定时器到期方法
if (widget.isFinish != null) {
widget.isFinish!(true);
}
_timer.cancel();
}else{
endTime = surplusTime;
}
});
}
break;
case AppLifecycleState.paused://不可见,后台
//进入后台再走inactive
outTime = DateTime.now().millisecondsSinceEpoch;
print("后台:$outTime");
break;
case AppLifecycleState.detached://不活跃
print("detached");
break;
}
}
@override
void dispose() {
if (!mounted || _timer?.isActive == true) {
_timer?.cancel();
}
WidgetsBinding.instance?.removeObserver(this);
super.dispose();
}
@override
Widget build(BuildContext context) {
//这里写Widget
return Container();
}
}