Flutter中点击TextField键盘瞬关,如何兼容Drawer功能?
问题解决:Flutter中Drawer与TextField同时正常工作的方案
问题根源
你的代码里scaffoldkey和TabController都定义在build方法内部,每次Widget重建(比如键盘弹出触发布局变化)时,这两个对象都会被重新实例化。Scaffold的key改变会导致整个Scaffold树重建,TextField因此失去焦点,键盘瞬间关闭。
修复步骤
把GlobalKey<ScaffoldState>和TabController移到State类的成员变量位置,避免每次build都重新创建:
修改后的完整代码
import 'package:flutter/material.dart'; import 'package:resturant/constant.dart'; import 'package:resturant/widgets/items.dart'; import 'package:resturant/widgets/sidemenu.dart'; import 'package:resturant/widgets/welcome.dart'; class HomePage extends StatefulWidget { const HomePage({super.key}); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> with TickerProviderStateMixin { // 移至State成员变量,确保仅初始化一次 final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); late TabController _tabController; @override void initState() { super.initState(); // 在initState中初始化TabController _tabController = TabController(length: 3, vsync: this); } @override void dispose() { // 销毁控制器,避免内存泄漏 _tabController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { double devicewidth = MediaQuery.of(context).size.width; double deviceheight = MediaQuery.of(context).size.height; return PopScope( canPop: false, child: SafeArea( child: Scaffold( resizeToAvoidBottomInset: false, backgroundColor: const Color(0xFFFFF5F5), key: _scaffoldKey, drawer: const SideMenu(), appBar: AppBar( backgroundColor: const Color(0xFFFFF5F5), title: IconButton( onPressed: () {}, icon: const Icon( Icons.shopping_cart_checkout_rounded, color: Color(0xffFF3A3A), size: 30, ), ), titleSpacing: devicewidth - 110, leading: IconButton( onPressed: () { _scaffoldKey.currentState!.openDrawer(); }, icon: const Icon( Icons.menu_rounded, color: Color(0xffFF3A3A), size: 35, ), ), automaticallyImplyLeading: false, ), body: Column( children: [ const Expanded(flex: 2, child: WelcomeWidget()), SizedBox( child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Padding( padding: EdgeInsets.only( left: defaultPadding + 10, top: 8, right: defaultPadding + 10), child: TextField( decoration: InputDecoration( prefixIconColor: Color(0xFFFF6666), filled: true, fillColor: Color(0xFFFFDDDD), prefixIcon: Icon(Icons.search), hintText: 'Search Food', hintStyle: TextStyle(color: Color(0xFFFF6666)), focusedBorder: OutlineInputBorder( borderSide: BorderSide( color: Color(0xFFFFDDDD), width: 0)), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(8)), borderSide: BorderSide( color: Color(0xFFFFDDDD), width: 0)), border: OutlineInputBorder( borderSide: BorderSide( color: Color(0xFFFFDDDD), width: 0), borderRadius: BorderRadius.all(Radius.circular(8)))), ), ), Padding( padding: const EdgeInsets.only(bottom: 15), child: TabBar( padding: EdgeInsets.zero, labelPadding: EdgeInsets.zero, indicatorPadding: EdgeInsets.zero, controller: _tabController, indicatorColor: const Color(0xffFF2B2B), labelColor: const Color(0xffFF2B2B), labelStyle: const TextStyle(fontWeight: FontWeight.bold), unselectedLabelColor: Colors.black, tabs: const [ Tab( text: 'Items', ), Tab( text: 'Combos', ), Tab( text: 'Deals', ), ], )) ], ), ), // List of food items Expanded( flex: deviceheight > 830 ? 8 : 8, child: TabBarView(controller: _tabController, children: [ const ItemsWidget(), Container( width: devicewidth, color: Colors.yellow, ), Container( width: devicewidth, color: Colors.black, ) ])), ], ), )), ); } }
关键修改说明
- 将
scaffoldkey改为State类的成员变量_scaffoldKey,用final修饰保证仅初始化一次,避免build时重复创建导致Scaffold重建 TabController移至成员变量,在initState中初始化,并在dispose方法中销毁,符合Flutter生命周期规范,避免内存泄漏- 所有原变量的引用替换为新的成员变量名
修改后,Scaffold的key不会随build重复创建,键盘弹出时不会触发Scaffold重建,TextField能保持焦点正常输入,同时Drawer也能通过key正常打开。
内容的提问来源于stack exchange,提问作者Mr Prime TO
相关产品推荐
相关产品推荐

