刚开始上手 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)
目前遇到的比较常见的问题就这么多,后续遇到了新问题再补充,持续更新中