I am designing a screen with two main sections:
- A carousel slider with a TextField below it
- A button
I want the button to be at the bottom of the screen.
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.
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.
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 ,