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

Flutter实现键盘弹出时组件先缩放后可滚动的登录界面

Flutter登录界面实现键盘弹出时先自适应布局再滚动

要实现键盘弹出时先让组件完成大小调整,空间不足时才允许滚动的效果,可以通过LayoutBuilder结合SingleChildScrollView和ConstrainedBox来实现,既保留原布局的自适应特性,又能在需要时启用滚动。

修改后的完整代码

return Scaffold(
  body: SafeArea(
    // 使用LayoutBuilder获取父容器的约束信息
    child: LayoutBuilder(
      builder: (context, constraints) {
        return SingleChildScrollView(
          child: ConstrainedBox(
            // 设置最小高度为父容器的最大高度,确保空间足够时Column撑满布局
            constraints: BoxConstraints(minHeight: constraints.maxHeight),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Flexible(flex: 2, child: Container()),
                Container(
                  padding: const EdgeInsets.symmetric(horizontal: 32),
                  child: Column(
                    children: [
                      SvgPicture.asset(
                        "assets/images/ic_instagram.svg",
                        colorFilter: ColorFilter.mode(isDarkMode ? primaryColor : Colors.black, BlendMode.srcIn),
                      ),
                      const SizedBox(height: 20.0),
                      InputTextField(
                        fillColor: isDarkMode ? Colors.grey.shade800 : Colors.grey[100],
                        borderSideColor: isDarkMode ? Colors.black : Colors.grey.shade400,
                        hintText: "Phone number, email or username",
                        textInputType: TextInputType.emailAddress,
                        textEditingController: _emailController,
                        isPassword: false,
                      ),
                      const SizedBox(height: 15.0),
                      InputTextField(
                        fillColor: isDarkMode ? Colors.grey.shade800 : Colors.grey[100],
                        borderSideColor: isDarkMode ? Colors.black : Colors.grey.shade400,
                        hintText: "Password",
                        textInputType: TextInputType.visiblePassword,
                        textEditingController: _passwordController,
                        isPassword: true,
                      ),
                      const SizedBox(height: 17.0),
                      CustomButton(
                        buttonContext: const Text(
                          "Log in",
                          style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
                        ),
                        onPressed: () {},
                      ),
                      const SizedBox(height: 9.0),
                      Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          GestureDetector(
                            onTap: () => print("a"),
                            child: const Padding(
                              padding: EdgeInsets.symmetric(vertical: 5.0),
                              child: Text(
                                "Forgot your login details? ",
                                style: TextStyle(color: Colors.grey, fontSize: 12.0, letterSpacing: 0.1),
                              ),
                            ),
                          ),
                          GestureDetector(
                            onTap: () => print("a"),
                            child: Padding(
                              padding: const EdgeInsets.symmetric(vertical: 5.0),
                              child: Text(
                                "Get help logging in.",
                                style: TextStyle(
                                    fontFamily: 'Roboto',
                                    color: isDarkMode ? Colors.white : Colors.purple.shade900,
                                    fontSize: 12.0,
                                    letterSpacing: 0.1,
                                    fontWeight: FontWeight.w700),
                              ),
                            ),
                          ),
                        ],
                      ),
                      const SizedBox(height: 5.0),
                      Row(
                        children: [
                          Expanded(
                            child: Divider(color: Colors.grey[400], height: 36),
                          ),
                          Padding(
                            padding: const EdgeInsets.symmetric(horizontal: 8.0),
                            child: Text(
                              "OR",
                              style: TextStyle(color: Colors.grey.shade600, fontWeight: FontWeight.bold),
                            ),
                          ),
                          Expanded(child: Divider(color: Colors.grey[400], height: 36)),
                        ],
                      ),
                      const SizedBox(height: 5.0),
                      CustomButton(
                        buttonContext: Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            SvgPicture.asset(
                              "assets/images/ic_facebook.svg",
                              colorFilter: const ColorFilter.mode(primaryColor, BlendMode.srcIn),
                            ),
                            const SizedBox(width: 8.0),
                            const Text(
                              'Logging in with Facebook',
                              style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
                            ),
                          ],
                        ),
                        onPressed: () {},
                      ),
                    ],
                  ),
                ),
                Flexible(flex: 1, child: Container()),
                Divider(color: Colors.grey[400], height: 36),
                Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    GestureDetector(
                      onTap: () => print("a"),
                      child: const Padding(
                        padding: EdgeInsets.symmetric(vertical: 5.0),
                        child: Text(
                          "Forgot your login details? ",
                          style: TextStyle(color: Colors.grey, fontSize: 12.0, letterSpacing: 0.1),
                        ),
                      ),
                    ),
                    GestureDetector(
                      onTap: () => print("a"),
                      child: Padding(
                        padding: const EdgeInsets.symmetric(vertical: 5.0),
                        child: Text(
                          "Get help logging in.",
                          style: TextStyle(
                              fontFamily: 'Roboto',
                              color: isDarkMode ? Colors.white : Colors.purple.shade900,
                              fontSize: 12.0,
                              letterSpacing: 0.1,
                              fontWeight: FontWeight.w700),
                        ),
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
        );
      },
    ),
  ),
);

关键修改说明

  1. LayoutBuilder:获取父容器的可用高度约束,动态设置Column的最小高度
  2. ConstrainedBox + minHeight:空间足够时让Column撑满父容器,保留原布局中Flexible的上下间距比例;键盘弹出导致高度不足时,Column总高度超过最小高度,SingleChildScrollView自动启用滚动
  3. 完全保留原有布局组件和样式,无需调整Flexible、间距等设置,完美兼容原设计

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 15:53:14