Flutter中Expansion Tile溢出及按钮显示异常的解决咨询
解决方案:修复ExpansionTile溢出与底部按钮显示不全问题
问题根源
你当前的代码存在两个核心问题:
- 给
SingleChildScrollView内部的Container设置了固定高度,当ExpansionTile展开后,内容高度超过固定值,导致底部按钮被挤出可视范围。 - 使用
MainAxisAlignment.spaceBetween在固定高度容器中布局,内容变长时会将底部元素推到容器外部。
修改后的完整代码
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class Address extends StatefulWidget { const Address({super.key}); @override State<Address> createState() => _AddressState(); } class _AddressState extends State<Address> { FocusNode addressText = FocusNode(); bool _open = false; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: AppBar( centerTitle: true, title: Container( width: 200, child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: LinearProgressIndicator( value: 1, backgroundColor: Color(0xD9D9D9D9), valueColor: AlwaysStoppedAnimation<Color>(Colors.blue), ), ), SizedBox(width: 7.0), Expanded( child: LinearProgressIndicator( value: 1, backgroundColor: Color(0xD9D9D9D9), valueColor: AlwaysStoppedAnimation<Color>(Colors.blue), ), ), SizedBox(width: 7.0), Expanded( child: LinearProgressIndicator( value: 0.15, backgroundColor: Color(0xD9D9D9D9), valueColor: AlwaysStoppedAnimation<Color>(Colors.blue), ), ), ], ), ) ), body: Column( children: [ // 可滚动的表单内容区域 Expanded( child: SingleChildScrollView( padding: EdgeInsets.all(30.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Enter your address",style: TextStyle(fontSize: 22,fontFamily: "GraphikMedium"),), SizedBox(height: 12,), Text("Enter the street address of your primary residence. Please do not use a PO box or business address", style: TextStyle(color: Colors.grey,fontSize: 16),), SizedBox(height: 24,), Text("Search for Address",style: TextStyle(fontSize: 16.0,fontFamily: "GraphikMedium", color: addressText.hasFocus ? Colors.blue : Colors.black), ), SizedBox(height: 8.0,), Focus( onFocusChange: (focus){ setState(() {}); }, child: TextFormField( focusNode: addressText, decoration: InputDecoration( enabledBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.grey), ), focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.blue) ), hintText: "Enter your address", hintStyle: TextStyle(color: Colors.grey) ), ), ), SizedBox(height: 40,), Theme( data: Theme.of(context).copyWith(dividerColor: Colors.transparent), child: ListTileTheme( contentPadding: EdgeInsets.all(0), dense: true, child: ExpansionTile( title: Text("Enter Address Manually",style: TextStyle(fontFamily: "GraphikRegular",fontSize: 16.0),), onExpansionChanged: (bool val) { setState(() { _open = val; }); }, children: [ Container( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 8.0,), Text("Address line 1",style: TextStyle(fontFamily: "GraphikRegular",fontSize: 16.0),), TextFormField( decoration: InputDecoration( enabledBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.grey) ), focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.blue), ) ), ), SizedBox(height: 8.0,), Text("Address line 2 (optional)",style: TextStyle(fontFamily: "GraphikRegular",fontSize: 16.0),), TextFormField( decoration: InputDecoration( enabledBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.grey) ), focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.blue), ) ), ), SizedBox(height: 8.0,), Text("City",style: TextStyle(fontFamily: "GraphikRegular",fontSize: 16.0),), TextFormField( decoration: InputDecoration( enabledBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.grey) ), focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.blue), ) ), ), SizedBox(height: 8.0,), Text("City",style: TextStyle(fontFamily: "GraphikRegular",fontSize: 16.0),), TextFormField( decoration: InputDecoration( enabledBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.grey) ), focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: Colors.blue), ) ), ), ], ), ) ], ), ), ) ], ), ), ), // 固定在底部的Continue按钮 Padding( padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 20.0), child: Container( width: MediaQuery.of(context).size.width, child: ElevatedButton( onPressed: (){ Navigator.pushNamed(context, '/user-purpose'); }, child: Text( "Continue", style: TextStyle( fontSize: 14.0, fontWeight: FontWeight.normal, color: Colors.white, fontFamily: "GraphikMedium", ), ), style: ButtonStyle( shape: MaterialStateProperty.all<RoundedRectangleBorder>( RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0)) ), minimumSize: MaterialStateProperty.all(Size.fromHeight(60.0)), backgroundColor: MaterialStateProperty.all(Colors.blue), shadowColor: MaterialStateProperty.all(Colors.transparent) ), ), ), ) ], ), ); } }
关键修改点
- 重构布局结构:将body改为
Column,分为可滚动的内容区和固定的按钮区,彻底避免按钮被挤出的问题。 - 移除固定高度限制:删除了Container的固定height设置,让
Expanded自动适配屏幕剩余空间,内容超出时自动滚动。 - 消除重复代码:去掉了原代码中重复的布局块,仅保留一套表单逻辑,通过ExpansionTile的状态控制展开/收起。
- 优化按钮定位:给底部按钮添加了上下内边距,确保按钮不会紧贴屏幕边缘,同时始终保持在可视区域底部。
内容的提问来源于stack exchange,提问作者Name
相关产品推荐
相关产品推荐

