Home > Enterprise >  How to avoid RenderFlow error when keyboard appears in Flutter
How to avoid RenderFlow error when keyboard appears in Flutter

Time:11-25

I am designing a screen with two main sections:

  1. A carousel slider with a TextField below it
  2. A button

I want the button to be at the bottom of the screen.

enter image description here

To achieve this, I have wrapped the column for 1. in a Flexible widget and set the mainAxisSize for the Column to max, and the mainAxis size for the Column containing the button to min.

Now when I click on the TextField, the keyboard appears, and I receive a Bottom Overflowed error with the Button appearing on top of the TextField.

enter image description here

How do I ensure that the Button stays at the bottom of the screen when the keyboard appears? I have tried wrapping both the Columns in another Column which in turn had been wrapped by a SingleChildScrollView widget, but that overrides the MainAxisSize.max property apparently, and renders the lower Column (containing the Button) just below the upper Column as seen below.

enter image description here

My Code:

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,
          child: SingleChildScrollView(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Flexible(
                  fit: FlexFit.loose,
                  child: Column(
                    mainAxisSize: MainAxisSize.max,
                    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(
                  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,),
                  ],
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

How do I get the Button to stay at the bottom of the screen even when the keyboard appears?

CodePudding user response:

Remove the Flexible and try the below code.

@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: GestureDetector(
          onTap: () {
            FocusManager.instance.primaryFocus?.unfocus();
          },
          behavior: HitTestBehavior.opaque,
          child: SingleChildScrollView(
            child: SizedBox(
              height: MediaQuery.of(context).size.height,
              width: MediaQuery.of(context).size.width,
              child: Column(
                children: [
                  CarouselSlider(
                    items: carouselImageList.map<Widget>((i) {
                      return Builder(builder: (context) {
                        return Container(
                          width: 100.w,
                          height: 100.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(
                              "Enter your phone number",
                              style: TextStyle(
                                  fontSize: 5.w, fontWeight: FontWeight.bold),
                            ),
                          ],
                        ),
                        SizedBox(height: 1.h),
                        TextFormField(
                          controller: phoneController,
                          keyboardType: TextInputType.phone,
                        ),
                        SizedBox(height: 1.h),
                        Text(
                          "OTP will be sent on this number.",
                          style: TextStyle(
                            fontSize: 3.w,
                          ),
                        ),
                      ],
                    ),
                  ),
                  Expanded(
                    child: Container(),
                  ),
                  Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      CustomButton(
                        width: 90.w,
                        height: 15.w,
                        color: primary!,
                        onTap: () {},
                        text: "Get OTP",
                        fontColor: white!,
                        borderColor: primary!,
                      ),
                      SizedBox(
                        height: 1.h,
                      ),
                      Text(
                        "By signing up, you agree to our Terms and Services",
                        style: TextStyle(
                          fontSize: 2.5.w,
                        ),
                      ),
                      SizedBox(
                        height: 2.h,
                      ),
                    ],
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }

CodePudding user response:

Wrap your Scaffold with a SingleChildScrollView widget and set the scroll direction to scrollDirection: Axis.vertical ,

  • Related