Flutter中FAB搭配键盘时RenderFlex溢出错误的解决方法
解决FAB集成输入框时的RenderFlex溢出问题
以下是针对该问题的具体修复方案:
核心问题分析
你的FAB使用了固定高度的Container,当TextFormField触发验证错误显示提示文本时,内容高度超过容器固定高度;同时body部分的Column布局未正确处理剩余空间,导致键盘弹出时布局挤压溢出。
具体修复步骤
1. 移除FAB容器的固定高度
去掉Container的height属性,改用Padding控制上下内边距,让容器自适应内容高度:
floatingActionButton: Container( width: ScreenSize.screenWidth*0.95, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8), ), padding: const EdgeInsets.symmetric(vertical: 8.0), // 替换固定高度为内边距 child: ... // 原有Row内容 ),
2. 优化TextFormField的空间适配
给TextFormField添加行数控制属性,同时限制错误提示行数,避免高度突增:
TextFormField( controller: _txtController, minLines: 1, maxLines: 3, // 允许输入框根据内容换行 decoration: InputDecoration( // 原有装饰内容 errorMaxLines: 2, // 限制错误提示行数 ), validator: (value) { if (value!.isEmpty) { return "Please enter a message"; } return null; }, ),
3. 修复Body部分的布局嵌套问题
原布局中SingleChildScrollView嵌套ListView会导致滚动冲突,且Column的MainAxisAlignment.spaceBetween无意义(仅一个子元素),改用Expanded包裹ListView,让聊天列表占据剩余空间:
body: SafeArea( child: Column( children: [ Expanded( // 用Expanded让列表占据剩余空间 child: Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: Consumer<MainProvider>( builder: (context, value, child) => isLoading ? const Center(child: CircularProgressIndicator()) : ListView.builder( padding: const EdgeInsets.symmetric(horizontal: 8.0), itemCount: value.chats.length, itemBuilder: (context, index) { debugPrint("${value.chats[index].erpId} == ${userP!.erp!}"); return Column( children: [ BubbleSpecialThree( text: value.chats[index].message!, color: const Color(0xFF1B97F3), tail: true, isSender: value.chats[index].sentBy == userP.erp! ? true : false, sent: value.chats[index].isReply==null ? true : !(value.chats[index].isReply!), seen: value.chats[index].readAt==null || value.chats[index].readAt=='' ? false : true, delivered: true, key: ValueKey(value.chats[index]), textStyle: const TextStyle( color: Colors.white, fontSize: 16), ), ], ).py8(); }, ), ), ), ), ], ), ),
4. 调整FAB内部Row布局
将Row的crossAxisAlignment改为CrossAxisAlignment.start,避免内容垂直居中导致的挤压,同时移除多余的SingleChildScrollView:
child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, // 修改为顶部对齐 children: [ Padding( padding: const EdgeInsets.symmetric(vertical: 4.0), child: SizedBox( width: context.screenWidth * 0.75, child: Form( key: _formKey, child: TextFormField( // 原有TextFormField内容 ), ), ), ), SizedBox(width: context.screenWidth * 0.04), IconButton( // 原有IconButton内容 ).centered() ], ),
修改后的完整代码片段
Scaffold( backgroundColor: const Color(0xfff5f5f5), resizeToAvoidBottomInset: true, floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, floatingActionButton: Container( width: ScreenSize.screenWidth*0.95, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8), ), padding: const EdgeInsets.symmetric(vertical: 8.0), child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.symmetric(vertical: 4.0), child: SizedBox( width: context.screenWidth * 0.75, child: Form( key: _formKey, child: TextFormField( controller: _txtController, minLines: 1, maxLines: 3, decoration: InputDecoration( alignLabelWithHint: true, label: Text( "Type a message*", textAlign: TextAlign.start, style: TextStyle( overflow: TextOverflow.visible, fontSize: 16, fontWeight: FontWeight.w400, color: const Color(0xFF1C1B1F).withOpacity(.74), ), ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), ), errorMaxLines: 2, ), validator: (value) { if (value!.isEmpty) { return "Please enter a message"; } return null; }, ), ), ), ), SizedBox(width: context.screenWidth * 0.04), IconButton( onPressed: () async { debugPrint("Saved Id: ${userP!.erp!}, sent id: ${widget.data.result!.user!.username} and name is: ${widget.data.result?.user?.name}"); if (_formKey.currentState!.validate()) { setState(() { change=false; }); final WhatAppMsgModel data = WhatAppMsgModel( message: _txtController.text, sentAt: DateTime.now(), sentBy: userP.erp, erpId: widget.data.result?.user?.username, teacherErp: userP.erp, activityId: widget.data.result!.activity!.toString(), contact: widget.data.result!.user!.contactNo!, isReply: false, ); bool isDone = await ActivityServices().sendWhatsAppMessages( data: data, isClasswise: widget.data.isClasswise!, ); if (isDone) { debugPrint("Yes, sent"); chatP.addMessage(data); _txtController.clear(); FocusManager.instance.primaryFocus?.unfocus(); } else { debugPrint("Nope"); if (context.mounted) { ScaffoldMessenger.of(context) .showSnackBar(const SnackBar( content: Text("Something went wrong"), )); } } } else { setState(() { change=true; }); } }, icon: const Icon( Icons.send, size: 36, )).centered() ], ), ), appBar: AppBar( backgroundColor: Colors.blueAccent, title: const Text('Conversation'), ), body: SafeArea( child: Column( children: [ Expanded( child: Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: Consumer<MainProvider>( builder: (context, value, child) => isLoading ? const Center(child: CircularProgressIndicator()) : ListView.builder( padding: const EdgeInsets.symmetric(horizontal: 8.0), itemCount: value.chats.length, itemBuilder: (context, index) { debugPrint("${value.chats[index].erpId} == ${userP!.erp!}"); return Column( children: [ BubbleSpecialThree( text: value.chats[index].message!, color: const Color(0xFF1B97F3), tail: true, isSender: value.chats[index].sentBy == userP.erp! ? true : false, sent: value.chats[index].isReply==null ? true : !(value.chats[index].isReply!), seen: value.chats[index].readAt==null || value.chats[index].readAt=='' ? false : true, delivered: true, key: ValueKey(value.chats[index]), textStyle: const TextStyle( color: Colors.white, fontSize: 16), ), ], ).py8(); }, ), ), ), ), ], ), ), ),
内容的提问来源于stack exchange,提问作者Shreyansh Sharma
相关产品推荐
相关产品推荐

