skip to Main Content

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.

Before keyboard is popped out

After keyboard

3

Answers


  1. 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 the SizedBox.

    const Expanded(child: SizedBox()),
    
    SizedBox(height: 16),
    

    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.

    Login or Signup to reply.
  2. I would suggest you using ConstrainedBox instead of SizedBox to set minimum height

    ConstrainedBox(
      constraints: new BoxConstraints(
        minHeight: 5.0,
      ),
    ),
    

    original answer: link

    Login or Signup to reply.
  3. To avoid that, just put

    resizeToAvoidBottomInset: false,
    

    in your Scaffold()

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search