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

Flutter中点击TextField后键盘立即收起的问题排查求助

问题:返回页面后TextField点击唤起键盘立即收起的异常

我有一个包含ListView和TextField的Flutter Widget,初始状态下点击TextField能正常唤起键盘;但当我输入内容后点击键盘外部收起键盘,再导航到其他页面并返回原页面时,再次点击TextField会出现键盘弹出后立即收起的异常情况。仅使用GestureDetector、ListView和TextField的情况下,可能是什么原因导致的?

以下是我的代码:

// ignore_for_file: prefer_const_constructors, prefer_const_literals_to_create_immutables
import 'dart:math';
import 'package:flutter/cupertino.dart' as cupertino;
import 'package:flutter/material.dart' hide BoxDecoration, BoxShadow;
import 'package:flutter/services.dart';
import 'package:flutter_animator/flutter_animator.dart';
import 'package:flutter_inset_box_shadow/flutter_inset_box_shadow.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:iknowApp/constant.dart';
import 'package:animated_theme_switcher/animated_theme_switcher.dart' as theme;
import 'package:like_button/like_button.dart';
import 'package:string_similarity/string_similarity.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../data/sentencesData.dart';
import '../data/sentencesDataEN.dart';
import '../data/sharedPreferences/sharedPreferences.dart';
import '../data/theme.dart';
import '../main.dart';

class QuizMode extends StatefulWidget {
  const QuizMode({
    Key key,
  }) : super(key: key);

  @override
  State<QuizMode> createState() => _QuizModeState();
}

class _QuizModeState extends State<QuizMode> {
  bool isPressed = false;
  var result;
  bool correct = true;
  int contador = 0;
  int quizScore = 0;
  final controller = TextEditingController();
  var list = sentences;
  // generates a new Random object
  var _random = new Random();
  var element;
  final formKey = GlobalKey();
  FocusNode myFocusNode;
  bool check = true;
  bool like1 = true;
  bool like2 = true;
  bool like3 = true;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    element = list[_random.nextInt(list.length)];
    myFocusNode = FocusNode();
  }

  @override
  void dispose() {
    myFocusNode.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    Offset distance = isPressed ? Offset(MediaQuery.of(context).size.height * 0.01, MediaQuery.of(context).size.height * 0.01) : Offset(MediaQuery.of(context).size.height * 0.03, MediaQuery.of(context).size.height * 0.03);
    double blur = isPressed ? 5 : 30;
    return !Constant.quizMode ? const MyHomePage() : theme.ThemeSwitchingArea(
      child: cupertino.GestureDetector(
        onTap: () {
          cupertino.FocusScope.of(context).unfocus();
        },
        child: Scaffold(
          body: SafeArea(
            child: cupertino.Center(
              child: ListView.builder(
                shrinkWrap: true,
                itemCount: 1,
                itemBuilder: (context, index) {
                  final answ = element.answer[index];
                  final ques = element.question[index];
                  return cupertino.Center(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      crossAxisAlignment: CrossAxisAlignment.center,
                      children: [
                        SizedBox(
                          height: contador < 3 ? MediaQuery.of(context).size.height * 0.1 : MediaQuery.of(context).size.height * 0.05,
                        ),
                        contador < 3 ? cupertino.Column(
                          children: [
                            cupertino.Padding(
                              padding: EdgeInsets.only(
                                  left: MediaQuery.of(context)
                                      .size
                                      .width *
                                      0.1,
                                  right: MediaQuery.of(context)
                                      .size
                                      .width *
                                      0.1),
                              child: cupertino.Center(
                                child: TextField(
                                  focusNode: myFocusNode,
                                  enabled: contador > 2 ? false : true,
                                  key: formKey,
                                  style: TextStyle(
                                    color: Constant.isDarkMode ? cupertino.Color.fromARGB(
                                        255, 179, 29, 29)
                                        .withOpacity(0.7) : cupertino.Color.fromARGB(
                                        255, 109, 4, 4),
                                  ),
                                  controller: controller,
                                  // onChanged: onSearchTextChanged,
                                  textAlign: TextAlign.left,
                                  onSubmitted: (value) async {
                                    print(result);
                                    if (value != "") {
                                      String answer = answ
                                          .toString()
                                          .toLowerCase();
                                      result = controller.text
                                          .toString()
                                          .toLowerCase()
                                          .similarityTo(answer);
                                      if (result.toDouble() > 0.5) {
                                        quizScore++;
                                        if (quizScore > Constant.score) {
                                          Constant.score = quizScore;
                                          await DataPreferences
                                              .setScore(
                                              Constant.score);
                                        }
                                        setState(() {
                                          contador = 0;
                                          _random = Random();
                                          element = list[
                                          _random.nextInt(
                                              list.length)];
                                          correct = true;
                                          controller.clear();
                                          myFocusNode
                                              .requestFocus();
                                        });
                                      } else {
                                        setState(() {
                                          correct = false;
                                          contador++;
                                          HapticFeedback
                                              .heavyImpact();
                                          if (contador == 1) {
                                            like3 = false;
                                          }
                                          if (contador == 2) {
                                            like2 = false;
                                          }
                                          if (contador == 3) {
                                            like1 = false;
                                          }
                                        });
                                      }
                                    }
                                  },
                                  decoration: InputDecoration(
                                    errorText: correct == false ? AppLocalizations.of(
                                        context)
                                        .incorrect : null,
                                    enabledBorder: UnderlineInputBorder(
                                      borderSide: BorderSide(
                                        color: Constant.isDarkMode ? cupertino.Color
                                            .fromARGB(255, 97, 55, 55)
                                            .withOpacity(0.7) : cupertino.Color
                                            .fromARGB(
                                            255, 77, 6, 6),
                                      ),
                                    ),
                                    hintText: AppLocalizations.of(context)
                                        .answer,
                                    hintStyle: TextStyle(
                                      fontSize: MediaQuery.of(context)
                                          .size
                                          .height *
                                          0.02,
                                      fontWeight: FontWeight.normal,
                                      color: Constant.isDarkMode ? cupertino.Color
                                          .fromARGB(255, 151, 111, 111)
                                          .withOpacity(0.7) : cupertino.Color
                                          .fromARGB(
                                          255, 59, 31, 104),
                                    ),
                                    focusedBorder: InputBorder.none,
                                  ),
                                ),
                              ),
                            ),
                          ],
                        ) : cupertino.Center(),
                        theme.ThemeSwitcher(builder: (context) {
                          return InkWell(
                            onTap: () {
                              setState(() {
                                Constant.bodyAnimation = true;
                                Constant.quizMode = false;
                              });
                            },
                            child: Text(AppLocalizations.of(context).returnn,
                              style: GoogleFonts.alike(
                                  textStyle: Theme.of(context)
                                      .textTheme
                                      .displayMedium,
                                  fontSize: MediaQuery.of(context)
                                      .size
                                      .width *
                                      0.04,
                                  color: Constant.isDarkMode ? cupertino.Color.fromARGB(
                                      255, 185, 51, 51)
                                      .withOpacity(0.7) : cupertino.Color.fromARGB(
                                      255, 158, 158, 158),
                              )),
                          );
                        }),
                      ],
                    ),
                  );
                },
              ),
            ),
          ),
        ),
      ),
    );
  }
}

分析与解决方案

这个问题我之前排查过类似的场景,核心原因和你页面里的GestureDetector以及FocusNode的状态管理有关,具体来说有这两点:

  • GestureDetector的全局点击事件冲突:你用GestureDetector包裹了整个页面,onTap里调用FocusScope.of(context).unfocus()来收起键盘。但当你从其他页面返回时,页面重建过程中这个GestureDetector的点击事件可能会被意外触发(比如手势识别的层级优先级问题),导致刚唤起的键盘立即被强制收起。
  • FocusNode的状态未正确重置:页面返回后,FocusNode可能残留着之前的失焦状态,或者在页面重建时没有正确重新关联焦点逻辑,导致唤起键盘的操作被打断。

针对你的代码,这里有几个具体的修复方案:

方案1:优化GestureDetector的行为,避免全局拦截

给GestureDetector添加behavior: HitTestBehavior.translucent属性,这样TextField的点击事件会优先被处理,不会被外层的GestureDetector拦截:

cupertino.GestureDetector(
  behavior: HitTestBehavior.translucent, // 添加这一行
  onTap: () {
    cupertino.FocusScope.of(context).unfocus();
  },
  child: Scaffold(...),
)

方案2:在页面返回时重置FocusNode状态

重写didChangeDependencies方法,在页面再次可见时重置FocusNode的状态,确保它能正常获取焦点:

@override
void didChangeDependencies() {
  super.didChangeDependencies();
  // 页面返回后,重置FocusNode的状态
  WidgetsBinding.instance.addPostFrameCallback((_) {
    myFocusNode.unfocus();
  });
}

额外优化:简化列表嵌套

你的ListView.builder设置了itemCount:1,其实完全可以用Column直接替代,减少不必要的列表嵌套,也能避免一些手势识别的层级冲突问题。

修改后测试一下:点击TextField唤起键盘,输入后点击外部收起,导航到其他页面再返回,再次点击TextField应该就能正常唤起键盘了。

内容的提问来源于stack exchange,提问作者Juan Sin Miedo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 16:52:47