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

Flutter编辑页TextFormField点击后键盘弹出即关闭问题求助

Flutter编辑个人资料页面键盘弹出后立即关闭/刷新问题

在Flutter项目的编辑个人资料页面中,点击TextFormField后,键盘会瞬间弹出随即关闭/刷新。已尝试以下解决方案但均无效:

  • 移除MediaQuery
  • 修改AndroidManifest.xml中的adjustResize属性
  • 移除Form的GlobalKey

页面代码

import 'package:abroad/models/user_model.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:line_awesome_flutter/line_awesome_flutter.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../../../constants/sizes.dart';
import '../../../../constants/text_strings.dart';
import '../../controllers/profile_controller.dart';

class UpdateProfileScreen extends StatefulWidget {
  const UpdateProfileScreen({Key? key}) : super(key: key);

  @override
  State<UpdateProfileScreen> createState() => _UpdateProfileScreenState();
}

class _UpdateProfileScreenState extends State<UpdateProfileScreen> {
  static final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    final controller = Get.put(ProfileController());
    return Scaffold(
      extendBodyBehindAppBar: true,
      appBar: AppBar(
        backgroundColor: Colors.transparent,
        elevation: 0,
        centerTitle: true,
        leading: IconButton(
            onPressed: () => Get.back(),
            icon: const Icon(LineAwesomeIcons.angle_left)),
        title: Text(
          tEditProfile,
          style: GoogleFonts.montserrat(
            fontWeight: FontWeight.bold,
          ),
        ),
      ),
      body: SingleChildScrollView(
        child: Container(
          width: double.infinity,
          height: MediaQuery.of(context).size.height,
          padding: const EdgeInsets.fromLTRB(
              tDefaultSize, tDefaultSize + 75, tDefaultSize, tDefaultSize),
          decoration: const BoxDecoration(
            image: DecorationImage(
              image: AssetImage(
                  "assets/images/profile_images/profile_screen_background.png"),
              fit: BoxFit.cover,
            ),
          ),
          child: FutureBuilder(
            future: controller.getUserData(),
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.done) {
                if (snapshot.hasData) {
                  UserModel user = snapshot.data as UserModel;
                  //controllers
                  final id = TextEditingController(text: user.id);
                  final email = TextEditingController(text: user.email);
                  final password = TextEditingController(text: user.password);
                  final fullName = TextEditingController(text: user.fullName);
                  final phoneNo = TextEditingController(text: user.phoneNo);

                  return Column(
                    children: [
                      Stack(
                        children: [
                          SizedBox(
                            width: 120.w,
                            height: 120.h,
                            child: ClipRRect(
                              borderRadius: BorderRadius.circular(100),
                              child: const Image(
                                image: AssetImage(
                                  "assets/images/profile_images/profile.png",
                                ),
                              ),
                            ),
                          ),
                          Positioned(
                            bottom: 0,
                            right: 0,
                            child: Container(
                              width: 35.w,
                              height: 35.h,
                              decoration: BoxDecoration(
                                  borderRadius: BorderRadius.circular(100),
                                  color: Colors.blue),
                              child: const Icon(
                                LineAwesomeIcons.camera,
                                color: Colors.black,
                                size: 20,
                              ),
                            ),
                          ),
                        ],
                      ),
                      SizedBox(height: 25.h),
                      Form(
                          key: _formKey,
                          child: Column(
                            children: [
                              TextFormField(
                                controller: fullName,
                                style: const TextStyle(
                                  color: Colors.white,
                                ),
                                decoration: const InputDecoration(
                                    label: Text(tFullName),
                                    prefixIcon:
                                        Icon(Icons.person_outline_rounded)),
                              ),
                              SizedBox(height: tFormHeight - 10.h),
                              TextFormField(
                                controller: email,
                                style: const TextStyle(
                                  color: Colors.white,
                                ),
                                decoration: const InputDecoration(
                                    label: Text(tEmail),
                                    prefixIcon: Icon(Icons.email_outlined)),
                              ),
                              SizedBox(height: tFormHeight - 10.h),
                              TextFormField(
                                controller: phoneNo,
                                style: const TextStyle(
                                  color: Colors.white,
                                ),
                                decoration: const InputDecoration(
                                    label: Text(tPhoneNo),
                                    prefixIcon: Icon(Icons.numbers)),
                              ),
                              SizedBox(height: tFormHeight - 10.h),
                              TextFormField(
                                controller: password,
                                obscureText: true,
                                enableSuggestions: false,
                                autocorrect: false,
                                style: const TextStyle(
                                  color: Colors.white,
                                ),
                                decoration: const InputDecoration(
                                    label: Text(tPassword),
                                    prefixIcon: Icon(Icons.fingerprint)),
                              ),
                              const SizedBox(height: tFormHeight),
                              SizedBox(
                                width: 200.w,
                                child: ElevatedButton(
                                  onPressed: () async {
                                    final userData = UserModel(
                                      id: id.text,
                                      email: email.text.trim(),
                                      password: password.text.trim(),
                                      fullName: fullName.text.trim(),
                                      phoneNo: phoneNo.text.trim(),
                                    );
                                    await controller.updateRecord(userData);
                                  },
                                  style: ElevatedButton.styleFrom(
                                    minimumSize: const Size(175, 50),
                                    shape: RoundedRectangleBorder(
                                      borderRadius: BorderRadius.circular(30),
                                      side: const BorderSide(
                                          color: Colors.white, width: 2),
                                    ),
                                    backgroundColor: Colors.transparent,
                                  ),
                                  child: const Text(tEditProfile,
                                      style: TextStyle(color: Colors.white)),
                                ),
                              ),
                            ],
                          ))
                    ],
                  );
                } else if (snapshot.hasError) {
                  return Center(child: Text(snapshot.error.toString()));
                } else {
                  return const Center(child: Text('Something went wrong'));
                }
              } else {
                return Center(child: CircularProgressIndicator());
              }
            },
          ),
        ),
      ),
    );
  }
}

问题根源

你将TextEditingController的创建放在了FutureBuilder的builder方法内部,每次Widget重建(比如键盘弹出触发布局变化)时,都会重新创建一批新的控制器,导致原来的控制器被销毁,TextFormField失去焦点,键盘随即关闭。

修复方案

将所有TextEditingController移到State类的成员变量中,在initState或Future完成后初始化,避免每次build重建:

修改后的代码

import 'package:abroad/models/user_model.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:line_awesome_flutter/line_awesome_flutter.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../../../constants/sizes.dart';
import '../../../../constants/text_strings.dart';
import '../../controllers/profile_controller.dart';

class UpdateProfileScreen extends StatefulWidget {
  const UpdateProfileScreen({Key? key}) : super(key: key);

  @override
  State<UpdateProfileScreen> createState() => _UpdateProfileScreenState();
}

class _UpdateProfileScreenState extends State<UpdateProfileScreen> {
  static final _formKey = GlobalKey<FormState>();
  // 声明控制器为State成员变量
  late TextEditingController id;
  late TextEditingController email;
  late TextEditingController password;
  late TextEditingController fullName;
  late TextEditingController phoneNo;
  final controller = Get.put(ProfileController());

  @override
  void initState() {
    super.initState();
    // 初始化用户数据与控制器
    _initUserData();
  }

  void _initUserData() async {
    UserModel user = await controller.getUserData();
    setState(() {
      id = TextEditingController(text: user.id);
      email = TextEditingController(text: user.email);
      password = TextEditingController(text: user.password);
      fullName = TextEditingController(text: user.fullName);
      phoneNo = TextEditingController(text: user.phoneNo);
    });
  }

  @override
  void dispose() {
    // 销毁控制器,避免内存泄漏
    id.dispose();
    email.dispose();
    password.dispose();
    fullName.dispose();
    phoneNo.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      extendBodyBehindAppBar: true,
      appBar: AppBar(
        backgroundColor: Colors.transparent,
        elevation: 0,
        centerTitle: true,
        leading: IconButton(
            onPressed: () => Get.back(),
            icon: const Icon(LineAwesomeIcons.angle_left)),
        title: Text(
          tEditProfile,
          style: GoogleFonts.montserrat(
            fontWeight: FontWeight.bold,
          ),
        ),
      ),
      body: SingleChildScrollView(
        child: Container(
          width: double.infinity,
          height: MediaQuery.of(context).size.height,
          padding: const EdgeInsets.fromLTRB(
              tDefaultSize, tDefaultSize + 75, tDefaultSize, tDefaultSize),
          decoration: const BoxDecoration(
            image: DecorationImage(
              image: AssetImage(
                  "assets/images/profile_images/profile_screen_background.png"),
              fit: BoxFit.cover,
            ),
          ),
          child: FutureBuilder(
            future: controller.getUserData(),
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.done) {
                if (snapshot.hasData) {
                  return Column(
                    children: [
                      Stack(
                        children: [
                          SizedBox(
                            width: 120.w,
                            height: 120.h,
                            child: ClipRRect(
                              borderRadius: BorderRadius.circular(100),
                              child: const Image(
                                image: AssetImage(
                                  "assets/images/profile_images/profile.png",
                                ),
                              ),
                            ),
                          ),
                          Positioned(
                            bottom: 0,
                            right: 0,
                            child: Container(
                              width: 35.w,
                              height: 35.h,
                              decoration: BoxDecoration(
                                  borderRadius: BorderRadius.circular(100),
                                  color: Colors.blue),
                              child: const Icon(
                                LineAwesomeIcons.camera,
                                color: Colors.black,
                                size: 20,
                              ),
                            ),
                          ),
                        ],
                      ),
                      SizedBox(height: 25.h),
                      Form(
                          key: _formKey,
                          child: Column(
                            children: [
                              TextFormField(
                                controller: fullName,
                                style: const TextStyle(
                                  color: Colors.white,
                                ),
                                decoration: const InputDecoration(
                                    label: Text(tFullName),
                                    prefixIcon:
                                        Icon(Icons.person_outline_rounded)),
                              ),
                              SizedBox(height: tFormHeight - 10.h),
                              TextFormField(
                                controller: email,
                                style: const TextStyle(
                                  color: Colors.white,
                                ),
                                decoration: const InputDecoration(
                                    label: Text(tEmail),
                                    prefixIcon: Icon(Icons.email_outlined)),
                              ),
                              SizedBox(height: tFormHeight - 10.h),
                              TextFormField(
                                controller: phoneNo,
                                style: const TextStyle(
                                  color: Colors.white,
                                ),
                                decoration: const InputDecoration(
                                    label: Text(tPhoneNo),
                                    prefixIcon: Icon(Icons.numbers)),
                              ),
                              SizedBox(height: tFormHeight - 10.h),
                              TextFormField(
                                controller: password,
                                obscureText: true,
                                enableSuggestions: false,
                                autocorrect: false,
                                style: const TextStyle(
                                  color: Colors.white,
                                ),
                                decoration: const InputDecoration(
                                    label: Text(tPassword),
                                    prefixIcon: Icon(Icons.fingerprint)),
                              ),
                              const SizedBox(height: tFormHeight),
                              SizedBox(
                                width: 200.w,
                                child: ElevatedButton(
                                  onPressed: () async {
                                    final userData = UserModel(
                                      id: id.text,
                                      email: email.text.trim(),
                                      password: password.text.trim(),
                                      fullName: fullName.text.trim(),
                                      phoneNo: phoneNo.text.trim(),
                                    );
                                    await controller.updateRecord(userData);
                                  },
                                  style: ElevatedButton.styleFrom(
                                    minimumSize: const Size(175, 50),
                                    shape: RoundedRectangleBorder(
                                      borderRadius: BorderRadius.circular(30),
                                      side: const BorderSide(
                                          color: Colors.white, width: 2),
                                    ),
                                    backgroundColor: Colors.transparent,
                                  ),
                                  child: const Text(tEditProfile,
                                      style: TextStyle(color: Colors.white)),
                                ),
                              ),
                            ],
                          ))
                    ],
                  );
                } else if (snapshot.hasError) {
                  return Center(child: Text(snapshot.error.toString()));
                } else {
                  return const Center(child: Text('Something went wrong'));
                }
              } else {
                return Center(child: CircularProgressIndicator());
              }
            },
          ),
        ),
      ),
    );
  }
}

额外说明

  • 在dispose方法中销毁所有控制器,防止内存泄漏。
  • 将ProfileController实例放在State成员变量中,避免每次build重复调用Get.put创建实例。

内容的提问来源于stack exchange,提问作者Ibrahim Essam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 20:24:56