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

Flutter中如何实现键盘弹出时修改指定Widget的显示状态

功能实现说明

该需求完全可以实现,核心逻辑是通过监听键盘弹出时的系统布局偏移判断键盘状态,动态控制logo组件的显隐即可,具体实现方案如下:

实现步骤

  • 首先通过MediaQuery.of(context).viewInsets.bottom判断键盘状态:该值大于0代表键盘弹出,等于0代表键盘收起
  • 根据键盘状态,动态控制logo组件是否渲染,可搭配动画实现平滑的显隐过渡
  • 注意保持Scaffold的resizeToAvoidBottomInset属性为默认的true,否则无法正确检测键盘高度变化
  • 建议外层嵌套SingleChildScrollView,避免键盘弹出后表单内容溢出报错

修改后的完整代码

import 'package:flutter/material.dart';
import 'package:flutter_signin_button/button_list.dart';
import 'package:tembea/components/rounded_button.dart';
import 'package:tembea/constants.dart';
import 'package:flutter_signin_button/flutter_signin_button.dart';

class RegistrationScreen extends StatelessWidget {
  const RegistrationScreen({Key? key}) : super(key: key);
  static const String id =  'registration_screen';

  @override
  Widget build(BuildContext context) {
    // 检测键盘是否弹出
    final bool isKeyboardOpen = MediaQuery.of(context).viewInsets.bottom > 0;
    return Scaffold(
      backgroundColor: Colors.black,
      // 保持默认true,可响应键盘变化调整页面布局
      resizeToAvoidBottomInset: true,
      body: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 24.0),
        // 嵌套SingleChildScrollView防止内容溢出
        child: SingleChildScrollView(
          physics: const BouncingScrollPhysics(),
          child: SizedBox(
            // 高度占满屏幕,保证表单垂直居中
            height: MediaQuery.of(context).size.height,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                // 键盘弹出时隐藏logo,加淡入淡出动画更丝滑
                AnimatedOpacity(
                  opacity: isKeyboardOpen ? 0 : 1,
                  duration: const Duration(milliseconds: 200),
                  child: isKeyboardOpen ? const SizedBox.shrink() : Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Hero(
                        tag: 'logo',
                        child: SizedBox(
                          height: 100,
                          child: Image.asset('images/logo.png'),
                        ),
                      ),
                    ],
                  ),
                ),
                // 动态调整logo下方的间距
                AnimatedSize(
                  duration: const Duration(milliseconds: 200),
                  alignment: Alignment.topCenter,
                  child: SizedBox(height: isKeyboardOpen ? 0 : 20.0,),
                ),
                TextField(
                  textAlign: TextAlign.center,
                  style: const TextStyle(
                    color: Colors.white,
                  ),
                  onChanged: (value){},
                  decoration: kInputDecoration.copyWith(
                    hintText: 'Enter username',
                  ),
                ),
                const SizedBox(
                  height: 20.0,
                ),

                TextField(
                  textAlign: TextAlign.center,
                  style: const TextStyle(
                    color: Colors.white,
                  ),
                  onChanged: (value){},
                  decoration: kInputDecoration.copyWith(
                    hintText: 'Enter email',
                  ),
                ),
                const SizedBox(
                  height: 20.0,
                ),
                TextField(
                  textAlign: TextAlign.center,
                  obscureText: true,
                  style: const TextStyle(
                    color: Colors.white,
                  ),
                  onChanged: (value){},
                  decoration: kInputDecoration.copyWith(
                    hintText: 'Enter password',
                  ),
                ),
                const SizedBox(
                  height: 20.0,
                ),
                TextField(
                  textAlign: TextAlign.center,
                  obscureText: true,
                  style: const TextStyle(
                    color: Colors.white,
                  ),
                  onChanged: (value){},
                  decoration: kInputDecoration.copyWith(
                    hintText: 'Confirm password',
                  ),
                ),
                const SizedBox(
                  height: 20.0,
                ),
                RoundedButton(
                  buttonName: 'Register',
                  color: Colors.lightGreen,
                  onPressed: (){},
                ),
                const SizedBox(
                  height: 20,
                ),
                SignInButton(
                  Buttons.Google,
                  text: 'Sign Up with Google',
                  onPressed: (){},
                ),
                const SizedBox(
                  height: 20,
                ),
                Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    const Text(
                      'Already have an account?',
                      style: TextStyle(
                        color: Colors.white,
                      ),
                    ),
                    const SizedBox(
                      width: 5.0,
                    ),
                    TextButton(
                      onPressed: (){},
                      child: const Text(
                        'Sign In',
                        style: TextStyle(
                          color: Colors.green,
                        ),
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

额外优化说明

上述代码同时修复了原代码中两处布局问题:

  1. 原代码中Flexible组件直接作为Padding的子组件,不符合Flex组件的使用规范,会触发布局报错
  2. 原代码中Row内的间距用了SizedBox(height:5),应该改为宽度间距,避免出现错位问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 07:15:03