I’m working on a simple design for a login screen that has some content to display. The design looks perfect, as per the requirements.
But the issue is that when the keyboard is popped out, every widget’s internal vertical spacing shrinks, and the widgets have no spacing.
Using SingleChildScrollView as parent of Column puts other errors which are mentioned here
Here’s the code!
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:laundary_app/screens/signup_sreen.dart';
import 'package:laundary_app/utils/helpers/constants.dart';
import 'package:laundary_app/widgets/custom/custom_elevated_button.dart';
import 'package:laundary_app/widgets/custom/custom_text_field.dart';
class LoginScreen extends StatelessWidget {
static const String routeName = '/login';
const LoginScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: CustomScrollView(
slivers: [
SliverFillRemaining(
hasScrollBody: false,
child: Padding(
padding: const EdgeInsets.only(
top: Constants.fullPagePadding,
left: Constants.fullPagePadding,
right: Constants.fullPagePadding,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SvgPicture.asset(
'assets/vectors/sign_in.svg',
height: 150,
fit: BoxFit.fitHeight,
),
const Expanded(flex: 3, child: SizedBox()),
const Text(
'Welcome back!',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
fontFamily: 'Poppins',
),
),
const Expanded(
child: SizedBox(),
flex: 2,
),
CustomTextField(
hint: '[email protected]',
title: 'E-mail address',
controller: TextEditingController(),
onSubmitted: (value) {},
suffix: const Icon(Icons.alternate_email),
),
const Expanded(child: SizedBox()),
CustomTextField(
hint: 'Password',
title: 'Password',
controller: TextEditingController(),
onSubmitted: (value) {},
obscureText: true,
suffix: IconButton(
icon: const Icon(Icons.remove_red_eye_outlined),
onPressed: () {},
),
),
const Expanded(child: SizedBox()),
Align(
alignment: Alignment.centerRight,
child: TextButton(
onPressed: () {},
child: const Text('Forget Password'),
),
),
buildORDivider(),
const Expanded(child: SizedBox()),
buildSocialMediaButtons(),
const Expanded(flex: 2, child: SizedBox()),
CustomElevatedButton(
text: 'Log in',
icon: Icons.arrow_forward_sharp,
onTap: () {},
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Don't have an account'),
TextButton(
onPressed: () => Navigator.of(context)
.pushNamed(SignUpScreen.routeName),
child: const Text('Sign Up'),
),
],
)
],
),
),
),
],
),
),
);
}
Widget buildORDivider() {
return Row(
children: const [
Expanded(child: Divider(thickness: 1.5)),
Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Text('or'),
),
Expanded(child: Divider(thickness: 1.5)),
],
);
}
Widget buildSocialMediaButtons() {
// <a href="https://www.flaticon.com/free-icons/google" title="google icons">Google icons created by Freepik - Flaticon</a>
// <a href="https://www.flaticon.com/free-icons/facebook" title="facebook icons">Facebook icons created by Fathema Khanom - Flaticon</a>
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SocialMediaLoginButtonWidget(
imagePath: 'assets/images/google.png',
onPressed: () {},
),
const SizedBox(width: 30),
SocialMediaLoginButtonWidget(
imagePath: 'assets/images/facebook.png',
onPressed: () {},
),
],
);
}
}
class SocialMediaLoginButtonWidget extends StatelessWidget {
const SocialMediaLoginButtonWidget(
{Key? key, required this.imagePath, required this.onPressed})
: super(key: key);
final String imagePath;`enter code here`
final VoidCallback onPressed;
@override
Widget build(BuildContext context) {
return Container(
height: 60,
padding: const EdgeInsets.all(12.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(Constants.borderRadius),
),
child: Image.asset(
imagePath,
),
);
}
}
As a side note, here’s the output of both scenarios as well.
3
Answers
The expanded widgets are working as they are intended, expanding to fill the space that is available. When you have no space, they will shrink. If you want the space to remain and just scroll instead of squishing the expanded widgets, don’t use the expanded widgets. Either use padding or just remove the
Expanded
widget and define whatever height you want inside theSizedBox
.If the reason you were using Expanded is because you wanted spacing proportional to screen size, you can also use
MediaQuery.of(context).size.height
to calculate the padding you need.I would suggest you using
ConstrainedBox
instead ofSizedBox
to set minimum heightoriginal answer: link
To avoid that, just put
in your Scaffold()