刚开始上手 flutter 开发的时候,总会遇到这样那样的小问题,而官方文档又没有明确说明不能这样使用,本文总结了一些开发中经常会遇到的一些问题和一些开发小技巧。
Container(
color: Colors.green,
child: const Expanded(
child: Text('出错了!'),
),
)
以上使用将会报错,在 debug 模式下可以显示出来,但控制台会抛出异常,release 模式直接不显示,报错信息如下:
======== Exception caught by widgets library =======================================================
The following assertion was thrown while applying parent data.:
Incorrect use of ParentDataWidget.
The ParentDataWidget Expanded(flex: 1) wants to apply ParentData of type FlexParentData to a RenderObject, which has been set up to accept ParentData of incompatible type ParentData.
Usually, this means that the Expanded widget has the wrong ancestor RenderObjectWidget. Typically, Expanded widgets are placed directly inside Flex widgets.
The offending Expanded is currently placed inside a ColoredBox widget.
Container(
color: Colors.red,
decoration: const BoxDecoration(
color: Color(0xFFCE9F76),
borderRadius: BorderRadius.all(Radius.circular(10)),
),child: const Text('文本展示'),
)
上述用法将会报错,页面爆红展示错误信息:
======== Exception caught by widgets library =======================================================
The following assertion was thrown building HomePage(dirty, state: _HomePageState#57a29):
Cannot provide both a color and a decoration
To provide both, use "decoration: BoxDecoration(color: color)".
'package:flutter/src/widgets/container.dart':
Failed assertion: line 273 pos 15: 'color == null || decoration == null'
Column(
children: [
ListView.separated(
itemBuilder: (context, index) {
return ListTile(
title: Text('第$index项'),
);
},
separatorBuilder: (context, index) {
return const Divider(
color: Colors.orange,
);
},
itemCount: 20)
],
)
上述问题会抛出如下异常:
======== Exception caught by rendering library =====================================================
The following assertion was thrown during performResize():
Vertical viewport was given unbounded height.
Viewports expand in the scrolling direction to fill their container. In this case, a vertical viewport was given an unlimited amount of vertical space in which to expand. This situation typically happens when a scrollable widget is nested inside another scrollable widget.
If this widget is always nested in a scrollable widget there is no need to use a viewport because there will always be enough vertical space for the children. In this case, consider using a Column or Wrap instead. Otherwise, consider using a CustomScrollView to concatenate arbitrary slivers into a single scrollable.
错误说明很明显,垂直视口的高度没有边界,此时可以通过给 ListView 外面套一个具有固定高度的盒子比如 SizeBox 或者嵌套一个可扩展高度的组件 Expanded 解决
// 固定视口高度,此时无法准确填充屏幕剩余空间
Column(
children: [
SizedBox(
height: 500,
child: ListView.separated(
itemBuilder: (context, index) {
return ListTile(
title: Text('第$index项'),
);
},
separatorBuilder: (context, index) {
return const Divider(
color: Colors.orange,
);
},
itemCount: 20),
)
],
)
// 使用 Expanded 可以准确填充屏幕剩余空间
Column(
children: [
Expanded(
child: ListView.separated(
itemBuilder: (context, index) {
return ListTile(
title: Text('第$index项'),
);
},
separatorBuilder: (context, index) {
return const Divider(
color: Colors.orange,
);
},
itemCount: 20),
)
],
)
当列表项不是很多,或者存在列表嵌套,还可以通过下面的方式解决:
// 配置 ListView 的 shrinkWrap 属性
shrinkWrap: true,
注意:
Container(
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border:Border.all(color: Colors.red, width: 2),
),
// position: DecorationPosition.foreground,
child: Image.network(
'https://desk-fd.zol-img.com.cn/t_s960x600c5/g6/M00/03/0E/ChMkKWDZLXSICljFAC1U9uUHfekAARQfgG_oL0ALVUO515.jpg',
fit: BoxFit.cover,
width: 100,
height: 100,
errorBuilder: (context, error, stackTrace) => Image.asset(
'assets/images/4.0x/home/ic_round_rect_grey_60.png',
width: 100,
height: 100,
)),
)
上述圆角裁剪方式同时存在圆角与边框,会存在边框显示不全被裁剪的情况
此时可以对图片单独进行一次裁剪即可解决问题,或者更换其他圆角裁剪方式来替换 decoration
有 3 种解决方式:
1、可以通过给TextField设置如下属性来禁用这一提示,此时无法选中任何输入内容:
enableInteractiveSelection: false,
2、可以通过给TextField设置如下属性来禁用这一提示,此时可以选中输入内容但是不会有提示窗口:
toolbarOptions: ToolbarOptions()
3、如果要继续保留以上提示,可使用 flutter 提供的国际化来修改为中文显示:
// 配置依赖
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
// 增加国际化处理
return MaterialApp(
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate, //iOS
],
supportedLocales: [
const Locale('zh', 'CN'),
const Locale('en', 'US'),
]
}
通常可以通过在根布局中嵌套一层 SingleChildScrollView 来解决
resizeToAvoidBottomInset: false
behavior: HitTestBehavior.opaque
SafeArea(child: Colunm())
Container(
margin: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.circular(8),
),
child: Column(
children: List.generate(5, (index) {
return ListTile(title: Text('第$index个'));
}),
))
Padding(
padding: const EdgeInsets.all(10.0),
child: PhysicalModel(
borderRadius: BorderRadius.circular(10),
color: Colors.green,
clipBehavior: Clip.hardEdge,
child: Column(
children: List.generate(
5,
(index) => ListTile(
title: Text('第$index个'),
)),
)),
)
Padding(
padding: const EdgeInsets.all(10.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Container(
color: Colors.orange,
child: Column(
children: List.generate(
5,
(index) => ListTile(
title: Text('第几=$index个'),
)),
),
),
),
)
●使用 CircleAvatar 来实现:
Padding(
padding: EdgeInsets.all(10),
child: CircleAvatar(
radius: 50,
backgroundColor: Colors.white, //未设置背景色,加载图片时会显示红色
backgroundImage: NetworkImage(
"https://desk-fd.zol-img.com.cn/t_s960x600c5/g6/M00/03/0E/ChMkKWDZLXSICljFAC1U9uUHfekAARQfgG_oL0ALVUO515.jpg")),
)
Padding(
padding: const EdgeInsets.all(10),
child: ClipOval(
child: Image.network(
"https://desk-fd.zol-img.com.cn/t_s960x600c5/g6/M00/03/0E/ChMkKWDZLXSICljFAC1U9uUHfekAARQfgG_oL0ALVUO515.jpg",
width: 100,
height: 100,
fit: BoxFit.cover,
),
),
)
●使用 Container 配合 decoration 的 ShapeDecoration 可以实现多种不同的效果(只适用背景)
// 斜切角形状示例
Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
children: [
//斜切角形状示例
Container(
width: 120,
height: 120,
decoration: ShapeDecoration(
shape: BeveledRectangleBorder(
borderRadius: BorderRadius.circular(16)
),
image: const DecorationImage(
fit: BoxFit.cover,
image: NetworkImage('https://pic2.zhimg.com/v2-639b49f2f6578eabddc458b84eb3c6a1.jpg')
)
)
)
],
),
)
使用ShapeDecoration可以做出各种形状:
斜切角: BeveledRectangleBorder
圆角矩形: RoundedRectangleBorder
超椭圆: SuperellipseShape
体育场: StadiumBorder
圆形: CircleBorder
AnimatedList(itemBuilder: (context,index){
return ListTile(title: Text('第$index个'),)
})
InkWell(
onTap: (){},
child: Container(
// color: Colors.orange,
width: 100,
height: 100,
child: Text('点击水波效果')),
)
注意:
import 'package:myproject/MyCustomClass.dart' as myclass;
// 使用的时候:
myclass.CustomClassType _myCustom;
包裹 Visibility 组件(默认不占位):
Visibility(visible: true, child: Text('这里是一段文字'))
// 有几个属性需要注意一下:
child 子组件
visible 子组件是否可见,默认true(可见)
replacement 不可见时显示的组件(当maintainState = false)
maintainAnimation 不可见时,是否维持子组件中的动画
maintainSize 不可见时是否留有空间(设置为true)
maintainSemantics 不可见时是否维持它的语义
maintainInteractivity 不可见时是否具有交互性
注意:
maintainSize就是保持大小不变,如果只设置这个属性,会报错,
另外两个属性:maintainAnimation和maintainState也必须同时设置
Offstage(
offstage: true, // 子组件是否可见,默认true(隐藏)
child: Container(
color: Colors.green,
height: 100,
width: 100,
child: Text('这里是一段文字')))
当offstaged设置为true,子组件不可见,但仍处于activity状态。
如果不展示的时候有动画在执行,需要手动关闭动画
Opacity(
opacity: 0.1,
child: Container(
color: Colors.green,
height: 100,
width: 100,
child: Text('这里是一段文字')))
当设置透明度为0时,不展示,但在Widget Tree中存在。
如果不可见的时候需要占用大小,将alwaysIncludeSemantics设为true。
keyboardType: TextInputType.numberWithOptions(decimal: true)
目前遇到的比较常见的问题就这么多,后续遇到了新问题再补充,持续更新中