flutter 开发中的问题与技巧

news2025/2/23 12:54:50

一、概述

        刚开始上手 flutter 开发的时候,总会遇到这样那样的小问题,而官方文档又没有明确说明不能这样使用,本文总结了一些开发中经常会遇到的一些问题和一些开发小技巧。

二、常见问题


1、Expanded 组件只能在 Row、Column、Flex 中使用

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.


2、Container 组件中 color 和 decoration 不能同时设置

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'

3、Column、Row 等没有固定宽高的组件在嵌套 ListView、GridView 等可扩展宽高的组件会有异常抛出:

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,


注意:

  • 如果列表项过多,超过屏幕剩余可展示空间,屏幕会溢出
  • 这种方式只适用列表项不多的情况,性能不太好,会一次性渲染所有子 item
  • 当只需要外层滚动,内层列表不滚动时可以配置这个属性 physics: NeverScrollableScrollPhysics()

4、圆角矩形 border 被裁剪

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,
      )),
)

上述圆角裁剪方式同时存在圆角与边框,会存在边框显示不全被裁剪的情况 

Screenshot_20221129_152416.png


此时可以对图片单独进行一次裁剪即可解决问题,或者更换其他圆角裁剪方式来替换 decoration


5、TextField 长按出现复制粘贴的英文提示:

Screenshot_20221129_165224.png

有 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'),
  ]
}

三、开发技巧


1、键盘弹出后导致页面溢出

Screenshot_20221128_180138.png

通常可以通过在根布局中嵌套一层 SingleChildScrollView 来解决


2、键盘弹起会自动将页面顶上去,以保证键盘刚好在输入框下方(dialog 中不适用),有时候不需要顶起页面,可以在页面的 Scaffold 中如下配置禁止页面被顶起

resizeToAvoidBottomInset: false

Screenshot_20221128_190444.pngScreenshot_20221128_185026.png


3、使用GestureDetector的透明部分点击无效,导致点击范围很小,可以在 GestureDetector 里面加以下代码,提高点击的灵敏度:

behavior: HitTestBehavior.opaque


4、在部分机型上,页面底部与系统 home 导航条重叠了,尤其是在 iphone 系统上,出现此适配问题,以及 Android手机布局浸入到状态栏的问题,此时可以将页面根组件使用以下组件包裹来解决:

SafeArea(child: Colunm())


5、实现圆角的几种方式

  • 通过设置 Container 的 decoration 来实现:
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个'));
	  }),
	))

Screenshot_20221129_140144.png

  • 通过 PhysicalModel 来实现:
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个'),
                )),
      )),
)

Screenshot_20221129_141002.png

  • 通过 ClipRRect 实现
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个'),
                )),
      ),
    ),
  ),
)

Screenshot_20221129_141500.png


●使用 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")),
)

Screenshot_20221129_142505.png

  • 使用 ClipOval 实现,效果同上
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

image.png


6、想在添加或者删除列表项时添加对应的动画效果可以使用 AnimatedList 代替 ListView

AnimatedList(itemBuilder: (context,index){
  return ListTile(title: Text('第$index个'),)
})


7、添加Material触摸水波效果

InkWell(
  onTap: (){},
  child: Container(
      // color: Colors.orange,
      width: 100,
      height: 100,
      child: Text('点击水波效果')),
)

注意:

  • 如果子组件有设置颜色将会看不到水波效果
  • 必须设置点击事件监听,否则水波效果也不会触发

8、当引入的多个库有同名类冲突时,可以使用 as 制定别名解决:

import 'package:myproject/MyCustomClass.dart' as myclass;
// 使用的时候:
myclass.CustomClassType _myCustom;

9、控制组件可见性的几种方法:

  • 包裹 Visibility 组件(默认不占位):

Visibility(visible: true, child: Text('这里是一段文字'))

// 有几个属性需要注意一下:
child     子组件
visible   子组件是否可见,默认true(可见)
replacement 不可见时显示的组件(当maintainState = false)
maintainAnimation 不可见时,是否维持子组件中的动画 
maintainSize 不可见时是否留有空间(设置为true) 
maintainSemantics  不可见时是否维持它的语义
maintainInteractivity 不可见时是否具有交互性 

  注意:
  maintainSize就是保持大小不变,如果只设置这个属性,会报错,
  另外两个属性:maintainAnimation和maintainState也必须同时设置
  • 包裹 Offstage 组件(不占位):
Offstage(
    offstage: true, // 子组件是否可见,默认true(隐藏)
    child: Container(
        color: Colors.green,
        height: 100,
        width: 100,
        child: Text('这里是一段文字')))

当offstaged设置为true,子组件不可见,但仍处于activity状态。
如果不展示的时候有动画在执行,需要手动关闭动画
  • 包裹 Opacity 组件(占位,改变透明度):
Opacity(
    opacity: 0.1,
    child: Container(
        color: Colors.green,
        height: 100,
        width: 100,
        child: Text('这里是一段文字')))

当设置透明度为0时,不展示,但在Widget Tree中存在。
如果不可见的时候需要占用大小,将alwaysIncludeSemantics设为true。

10、如果两个叠加的widget,上面的widget不需要处理点击事件,下面的需要处理,可以在上面的widget中包裹一层IgnorePointer

11、如果TextFiled需要输入带有ip地址的数字,需要小数点.,可以如下设置

keyboardType: TextInputType.numberWithOptions(decimal: true)

四、总结

目前遇到的比较常见的问题就这么多,后续遇到了新问题再补充,持续更新中

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1088117.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

修改http_charfinder.py使能在python311环境中运行

需要修改两个函数&#xff0c;第一个是init函数&#xff0c;修改如下&#xff1a; async def init(loop, address, port): # <1> # app web.Application(looploop) # <2> # app.router.add_route(GET, /, home) # <3> app web.Application(…

AVPro Movie Capture☀️三、Unity录屏:录制摄像机指定区域

文章目录 🟥 录屏效果展示🟨 插件使用方法1️⃣ 导入插件2️⃣ 测试3️⃣ 移植到你的项目🟥 录屏效果展示 本插件是博主基于 “AVPro Movie Capture” 自制插件,该插件实现了: 录制摄像机指定区域画面的功能只有开始录制和停止录制两个API,简单不复杂其余功能完全基于…

【交付高质量,用户高增长】-用户增长质量保证方法论 | 京东云技术团队

前言 俗话说&#xff0c;“测试是质量的守护者”&#xff0c;但单凭测试本身却远远不够。大多数情况下&#xff0c;测试像“一面镜子”&#xff0c;照出系统的面貌&#xff0c;给开发者提供修改代码的依据&#xff0c;这个“照镜子”的过程&#xff0c;就是质量评估的过程&…

架构案例2017(五十二)

第5题 阅读以下关于Web系统架构设计的叙述&#xff0c;在答题纸上回答问题1至问题3.【说明】某电子商务企业因发展良好&#xff0c;客户量逐步增大&#xff0c;企业业务不断扩充&#xff0c;导致其原有的B2C商品交易平台己不能满足现有业务需求。因此&#xff0c;该企业委托某…

Bootstrap-媒体类型

加上媒体查询之后&#xff0c;只有在特定的设备之下才能起作用&#xff01;&#xff01;&#xff01;

【JWT】解密JWT:让您的Web应用程序更安全、更高效的神秘令牌

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于JWTElementUI的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.JWT是什么 JWT工作原理 JWT验证…

使用 flex 弹性盒保持容器均分布局

使用 flex 弹性盒保持容器均分布局 css 代码 .container {display: flex;width: 100%;height: 100vh; }.part {flex-grow: 1; /* 设置这个值就可以实现均匀分布&#xff0c;但是里面有内容会自动撑开 */flex-basis: 0; /* 为了防止自动撑开&#xff0c;设置基础值为 0 */ }如…

日常中msvcr120.dll丢失怎样修复?总结5个msvcr120.dll丢失的修复教程

在我日常的计算机维护工作中&#xff0c;经常遇到一些用户报告他们在运行某些程序时遇到了“MSVCR120.dll丢失”的问题。这是一个常见的DLL文件丢失或损坏问题&#xff0c;可能会对用户的计算机操作造成不便。在这篇心得体会中&#xff0c;我将分享一些关于这个问题的场景以及如…

JS截取url上面的参数

手动截取封装 function getUrlParams(url location.href) {let urlStr url.split(?)[1] || let obj {};let paramsArr urlStr.split(&)for (let i 0, len paramsArr.length; i < len; i) {const num paramsArr[i].indexOf()let arr [paramsArr[i].substring(0,…

vue监听watch或mutations

/mutations vue监听watch watch监听的属性的方法可以有两个值&#xff0c;一个新值&#xff0c;一个旧值 方法1: watch:{myVlaue:function(val,oldVal){}}方法2: //深度监听 watch:{pageSizeSel:{deep:true,handler:function () {this.pageCode1;this.getData();}},}当姓或…

这8款浏览器兼容性测试工具,用了以后测试效率可以“起飞”~~

浏览器的兼容性问题&#xff0c;是指不同浏览器使用内核及所支持的 HTML 等网页语言标准不同&#xff0c;用户客户端的环境不同造成的显示效果不能达到理想效果。 对于用户而言&#xff0c;无论使用哪款浏览器&#xff0c;期望看到的效果是正常的统一的。 市面上发布的浏览器…

【广州华锐互动】利用VR开展细胞基础实验教学有什么好处?

在科技发展的驱动下&#xff0c;虚拟现实&#xff08;VR&#xff09;技术已被广泛应用于各个领域&#xff0c;包括教育和医学。尤其是在医学教育中&#xff0c;VR技术已成为一种革新传统教学模式的有效工具。本文将探讨使用VR进行细胞基础实验教学的优势。 首先&#xff0c;VR技…

java中将金币格式化千分符和保留两位小数

public static String formatAmount(String amountStr) {try {// 将字符串金额解析为双精度类型double amount Double.parseDouble(amountStr);System.out.println("格式化之前: " amount);// 创建一个格式化器&#xff0c;设置千分位分隔符和保留两位小数NumberFo…

Diffusion Model论文/DALL E 2

B站视频学习记录 Ho J, Jain A, Abbeel P. Denoising diffusion probabilistic models[J]. Advances in neural information processing systems, 2020, 33: 6840-6851. Atwood J, Towsley D. Diffusion-convolutional neural networks[J]. Advances in neural information pro…

Python入门基础知识新手必备(赶紧收藏)

01 基本的类 python最基础、最常用的类主要有int整形&#xff0c;float浮点型&#xff0c;str字符串&#xff0c;list列表&#xff0c;dict字典&#xff0c;set集合&#xff0c;tuple元组等等。int整形、float浮点型一般用于给变量赋值&#xff0c;tuple元组属于不可变对象&am…

快捷高效的选择:Cpolar+Inis助你在Ubuntu上快速搭建博客网站

文章目录 前言1. Inis博客网站搭建1.1. Inis博客网站下载和安装1.2 Inis博客网站测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;2.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 3. 公网访问测试总…

IDEA—java: 常量字符串过长问题解决

问题描述&#xff1a; Error: java: 常量字符串过长 问题分析&#xff1a; 字符串长度过长&#xff0c;导致 idea 默认使用的 javac 编译器编译不了。 解决办法&#xff1a; Javac 编译器改为 Eclipse 编译器。 File -> Settings -> Build,Execution,Deployment -&…

Kafka 开启SASL/SCRAM认证 及 ACL授权(二)ACL

Kafka 开启SASL/SCRAM认证 及 ACL授权(二)ACL。 官网地址:https://kafka.apache.org/ kafka authentorization:https://docs.confluent.io/platform/current/kafka/authorization.html 一、开启ZK ACL(可选,内网环境,用户无机器访问权限时) 给kafka meta都加上zk的ac…

高版本Mac系统如何打开低版本的Xcode

这里写目录标题 前言解决方案 前言 大家偶尔也碰见过更新Mac系统后经常发现低版本的Xcode用不了的情况吧.基本每年大版本更新之后都可以在各个开发群里碰见问这个问题的. 解决方案 打开访达->应用程序->选中打不开的那个版本的Xcode并且右键显示包内容->Contents-…

mysql查询时间相关方法

查询当月第一天 SELECT DATE_FORMAT(NOW(), %Y-%m-01) AS first_day_of_month; SELECT DATE_FORMAT(CURDATE(), %Y-%m-01) AS first_day_of_month;查询当月最后一天 SELECT LAST_DAY(CURRENT_DATE) AS last_day_of_month;; SELECT LAST_DAY(NOW()) AS last_day_of_month查询当…