You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 04:47:33