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

Flutter键盘弹出时避免RenderFlow错误并固定底部按钮的方法

解决Flutter键盘弹出时按钮固定底部且避免溢出的问题

直接调整布局结构就能解决你的问题,核心是把可滚动的上部区域和固定的底部按钮区域拆分处理:

  1. 用Column作为主布局容器,让它占满整个屏幕空间
  2. 上部的轮播+输入框区域用Expanded包裹,内部嵌套SingleChildScrollView,这样既可以填充剩余空间,又能在内容被键盘挤压时滚动
  3. 底部按钮区域直接放在主Column的末尾,自然固定在屏幕底部

修改后的完整代码如下:

class SigninScreen extends StatefulWidget {
  const SigninScreen({super.key});

  @override
  State<SigninScreen> createState() => _SigninScreenState();
}

class _SigninScreenState extends State<SigninScreen> {

  int _currentCarouselIndex = 0;

  List<Widget> indicators(imagesLength, currentIndex) {
    return List<Widget>.generate(imagesLength, (index) {
      return Container(
        margin: EdgeInsets.symmetric(
          vertical: 1.h,
          horizontal: 2,
        ),
        width: currentIndex == index ? 15 : 10,
        height: 3,
        decoration: BoxDecoration(
          color: currentIndex == index ? primary : grey,
          borderRadius: const BorderRadius.all(
            Radius.circular(2),
          ),
        ),
      );
    });
  }

  TextEditingController phoneController = TextEditingController();

  @override
  void dispose() {
    phoneController.dispose(); 
    super.dispose();
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: GestureDetector(
          onTap: (){ FocusManager.instance.primaryFocus?.unfocus();},
          behavior: HitTestBehavior.opaque,
          // 主布局改为Column,占满整个屏幕
          child: Column(
            mainAxisSize: MainAxisSize.max,
            children: [
              // 上部可滚动区域用Expanded包裹,填充剩余空间
              Expanded(
                child: SingleChildScrollView(
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      CarouselSlider(
                        items: carouselImageList.map<Widget>((i){
                          return Builder(
                            builder: (context){
                              return Container(
                                width: 100.w,
                                height: 83.w,
                                decoration: BoxDecoration(
                                  image: DecorationImage(image: AssetImage(i), fit: BoxFit.fill),
                                ),
                              );
                            }
                          );
                        }).toList(), 
                        options: CarouselOptions(
                          height: 83.w,
                          aspectRatio: 1/0.83,
                          autoPlay: true,
                          autoPlayInterval: const Duration(seconds: 3),
                          initialPage: 0,
                          viewportFraction: 1,
                          onPageChanged: (index, timed) {
                            setState(() {
                              _currentCarouselIndex = index;
                            });
                          }
                        ),
                      ),
                      SizedBox(height: 1.h,),
                      Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: indicators(
                            carouselImageList.length, _currentCarouselIndex),
                      ),
                      SizedBox(height: 2.h,),
                      Padding(
                        padding: EdgeInsets.symmetric(horizontal: 5.w),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Row(
                              children: [
                                Text(isEnglish ? "Enter your phone number" : "अपना फ़ोन नंबर दर्ज करें", style: globalTextStyle.copyWith(fontSize: 5.w, fontWeight: FontWeight.bold),),
                              ],
                            ),
                            SizedBox(height: 1.h),
                            PhoneNumberField(phoneController: phoneController),
                            SizedBox(height: 1.h),
                            Text(isEnglish ? "OTP will be sent on this number." : "इस नंबर पर ओटीपी भेजा जाएगा।", style: globalTextStyle.copyWith(fontSize: 3.w,),),
                          ],
                        ),
                      ),
                    ],
                  ),
                ),
              ),
              // 底部按钮区域直接放在主Column末尾,固定在底部
              Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  CustomButton(width: 90.w, height: 15.w, color: primary, onTap: (){
                    // Navigator.pushNamed(context, otp);
                    (phoneController.text.length == 10) ?
                      Navigator.push(context, MaterialPageRoute(builder: (context) => 
                      OTPScreen(phoneNumber: "+91${phoneController.text}"))) 
                      : ShowSnackbar.showSnackBar(context, isEnglish ? "Enter a valid 10 digit phone number." : "एक मान्य 10 अंकों का फ़ोन नंबर दर्ज करें।");
                  }, text: isEnglish ? "Get OTP" : "ओटीपी प्राप्त करें", fontColor: white, borderColor: primary,),
                  SizedBox(height: 1.h,),
                  Text(isEnglish ? "By signing up, you agree to our Terms and Services" : "साइन अप करके, आप हमारी शर्तों से सहमत होते हैं और सेवाएं", style: globalTextStyle.copyWith(fontSize: 2.5.w,),),
                  SizedBox(height: 2.h,),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }
}

这样调整后:

  • 键盘弹出时,屏幕布局会自动调整,按钮始终保持在屏幕底部
  • 上部的轮播和输入框区域会变成可滚动状态,避免出现底部溢出错误
  • 收起键盘后,按钮会回到原来的底部位置,布局恢复正常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 17:46:07