0

Ok so I've spent the last 3 days watching singlechildscroll videos and reading forums and everyone says use singlechildscroll. For the life of me I can not get this widget to work with my signup page. I've placed this widget at almost every level and wrapping it in expanded and outside expanded amongst other widgets like containers or paddings with special viewinset.bottom settings and its just been a nightmare the amount of variances I've tried and still cant figure this out so I'm reaching out cause I'm out of ideas now.

import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:vext/controllers/auth_controller.dart';
import 'package:vext/helpers/constants.dart';
import 'package:vext/screens/login_screen.dart';
import 'package:vext/widgets/decorativeWidgets/rounded_text_form_field.dart';
import 'package:vext/widgets/decorativeWidgets/vext_elevated_button.dart';

import 'login_title.dart';

class SignUp extends StatefulWidget {
  const SignUp({Key? key}) : super(key: key);

  @override
  State<SignUp> createState() => _SignUpState();
}

class _SignUpState extends State<SignUp> {
  final _signUpFormKey = GlobalKey<FormState>();
  final TextEditingController _nameController = TextEditingController();
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();
  final _authController = Get.find<AuthController>();

  final FocusNode _nameFocus = FocusNode();
  final FocusNode _emailFocus = FocusNode();
  final FocusNode _passwordFocus = FocusNode();
  final FocusNode _passwordConfirmFocus = FocusNode();

  bool _isLoading = false;

  @override
  void dispose() {
    _nameController.dispose();
    _emailController.dispose();
    _passwordController.dispose();
    _authController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    bool keyboardIsOpen = MediaQuery.of(context).viewInsets.bottom != 0;
    debugPrint('New user Sign Up Initiated');
    return SafeArea(
      child: Scaffold(
        resizeToAvoidBottomInset: false,
        backgroundColor: kPrimaryColor,
        body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            SizedBox(
              height: 40.h,
            ),
            LoginTitle(
              title: 'Sign Up',
              subtitle: 'Create an account...',
              titleFontSize: 75.sp,
              subFontSize: 25.sp,
            ),
            SizedBox(height: 15.h),
            buildSignUpForm(),
            SizedBox(height: 30.h),
            Text(
              'Already have an account?',
              style: TextStyle(
                fontSize: 20.sp,
              ),
            ),
            TextButton(
              onPressed: () {
                FocusScope.of(context).unfocus();
                Get.to(() => LoginScreen());
              },
              child: Text(
                'Sign In',
                style: TextStyle(
                  color: kSecondaryColor,
                  fontSize: 20.sp,
                ),
              ),
              style: ButtonStyle(
                overlayColor: MaterialStateColor.resolveWith((states) => Colors.transparent),
              ),
            ),
            // Padding(
            //   padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
            // ),
          ],
        ),
      ),
    );
  }

  // Sign-up form Section
  Form buildSignUpForm() {
    return Form(
      key: _signUpFormKey,
      child: Column(
        children: <Widget>[
          RoundedTextFormField(
            autoFocus: true,
            focusNode: _nameFocus,
            onFieldSubmitted: (term) {
              _fieldFocusChange(context, _nameFocus, _emailFocus);
            },
            keyboardType: TextInputType.name,
            keyboardAction: TextInputAction.next,
            controller: _nameController,
            hintText: 'Name',
            validator: (value) {
              if (value.toString().length <= 2 || value!.isEmpty) {
                return 'Enter a valid Name';
              }
              return '';
            },
          ),
          SizedBox(height: 10.h),
          RoundedTextFormField(
            focusNode: _emailFocus,
            onFieldSubmitted: (term) {
              _fieldFocusChange(context, _emailFocus, _passwordFocus);
            },
            keyboardType: TextInputType.emailAddress,
            keyboardAction: TextInputAction.next,
            controller: _emailController,
            hintText: 'Email',
            validator: (value) {
              bool _isEmailValid =
                  RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+").hasMatch(value!);
              if (!_isEmailValid || value.isEmpty) {
                return 'Invalid Email';
              }
              return '';
            },
          ),
          SizedBox(height: 10.h),
          RoundedTextFormField(
            focusNode: _passwordFocus,
            onFieldSubmitted: (term) {
              _fieldFocusChange(context, _passwordFocus, _passwordConfirmFocus);
            },
            keyboardType: TextInputType.visiblePassword,
            keyboardAction: TextInputAction.next,
            obsecureText: true,
            controller: _passwordController,
            hintText: 'Password',
            validator: (value) {
              if (value.toString().length < 7 || value!.isEmpty) {
                return 'Password should be longer or equal to 7 characters.';
              }
              return '';
            },
          ),
          SizedBox(height: 10.h),
          RoundedTextFormField(
            focusNode: _passwordConfirmFocus,
            keyboardAction: TextInputAction.done,
            onFieldSubmitted: (term) {
              _passwordConfirmFocus.unfocus();
              //Get.to(() => LoginScreen());
            },
            keyboardType: TextInputType.visiblePassword,
            obsecureText: true,
            hintText: 'Confirm Password',
            validator: (value) {
              if (value!.trim() != _passwordController.text.trim() || value.isEmpty) {
                return 'Passwords do not match!';
              }
              return '';
            },
          ),
          SizedBox(height: 30.h),
          _isLoading
              ? const CircularProgressIndicator() // TODO custom progress indicator
              : VextElevatedButton(
                  buttonText: 'Sign Up',
                  onPressed: () {
                    debugPrint('Signup Submit button Pressed');
                    if (_signUpFormKey.currentState!.validate()) {
                      _signUpFormKey.currentState!.save();
                      setState(() {
                        _isLoading = true;
                      });
                      FocusScope.of(context).unfocus();
                      String name = _nameController.text.trim();
                      String email = _emailController.text.trim();
                      String password = _passwordController.text.trim();

                      debugPrint('Attempting Signup with Firebase');
                      _authController.signUp(name, email, password);
                      setState(() {
                        _isLoading = false;
                      });
                    }
                  },
                ),
        ],
      ),
    );
  }
}

_fieldFocusChange(BuildContext context, FocusNode currentFocus, FocusNode nextFocus) {
  currentFocus.unfocus();
  FocusScope.of(context).requestFocus(nextFocus);
}

The few times I got the screen to scroll at all the keyboard would push everything up but when the keyboard would close the page contents would stay at the raised level but scrollable.

Any help would be most appreciated

EDIT*

Here are the 2 custom Widgets that I can think of that are used in the signup screen

roundedTextFormfield

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:vext/helpers/constants.dart';

class RoundedTextFormField extends StatelessWidget {
  const RoundedTextFormField({
    Key? key,
    this.controller,
    required this.hintText,
    this.obsecureText = false,
    required this.validator,
    this.keyboardType = TextInputType.text,
    this.keyboardAction = TextInputAction.next,
    this.focusNode,
    this.onFieldSubmitted,
    this.autoFocus = false,
    this.errorText,
    this.onChanged,
    this.initialValue,
  }) : super(key: key);

  final TextEditingController? controller;
  final bool? obsecureText;
  final String? hintText;
  final String? Function(String?) validator;
  final TextInputType? keyboardType;
  final TextInputAction keyboardAction;
  final FocusNode? focusNode;
  final Function(String)? onFieldSubmitted;
  final bool? autoFocus;
  final String? errorText;
  final Function(String)? onChanged;
  final String? initialValue;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.symmetric(horizontal: 18.0.w),
      child: TextFormField(
        initialValue: initialValue,
        onChanged: onChanged,
        cursorColor: kSecondaryColor,
        autofocus: autoFocus!,
        keyboardType: keyboardType,
        textInputAction: keyboardAction,
        focusNode: focusNode,
        onFieldSubmitted: onFieldSubmitted,
        style: TextStyle(color: Theme.of(context).colorScheme.secondary),
        controller: controller,
        obscureText: obsecureText!,
        decoration: InputDecoration(
          errorStyle: TextStyle(
            color: Colors.orange,
            fontSize: 10.sp,
            fontWeight: FontWeight.bold,
          ),
          hintText: hintText,
          hintStyle: TextStyle(color: Theme.of(context).colorScheme.secondary),
          focusedBorder: OutlineInputBorder(
            borderSide: BorderSide(
              color: Theme.of(context).colorScheme.secondary,
              width: 2.w,
            ),
            borderRadius: BorderRadius.all(
              Radius.circular(30.0.r),
            ),
          ),
          enabledBorder: OutlineInputBorder(
            borderSide: BorderSide(
              color: Theme.of(context).colorScheme.secondary,
              width: 2.w,
            ),
            borderRadius: BorderRadius.all(
              Radius.circular(30.0.r),
            ),
          ),
          errorBorder: OutlineInputBorder(
            borderSide: BorderSide(
              color: Theme.of(context).errorColor,
              width: 2.w,
            ),
            borderRadius: BorderRadius.all(
              Radius.circular(30.0.r),
            ),
          ),
          focusedErrorBorder: OutlineInputBorder(
            borderSide: BorderSide(
              color: Theme.of(context).errorColor,
              width: 2.w,
            ),
            borderRadius: BorderRadius.all(
              Radius.circular(30.0.r),
            ),
          ),
        ),
        validator: validator,
      ),
    );
  }
}

and the other of an elevated button

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';

class VextElevatedButton extends StatelessWidget {
  const VextElevatedButton({
    Key? key,
    required this.buttonText,
    required this.onPressed,
    this.fontSize = 20,
  }) : super(key: key);

  final String? buttonText;
  final double? fontSize;
  final VoidCallback onPressed;

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onPressed,
      child: Text(
        buttonText!,
        style: TextStyle(
          fontSize: 20.sp,
        ),
      ),
      style: ElevatedButton.styleFrom(
        elevation: 20,
        shadowColor: Theme.of(context).colorScheme.secondary,
        minimumSize: Size(context.width * 0.4.w, context.height * 0.065.h),
        onPrimary: Theme.of(context).colorScheme.secondary,
        textStyle: TextStyle(color: Theme.of(context).colorScheme.secondary),
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(30.r),
          side: BorderSide(
            width: 2.w,
            color: Theme.of(context).colorScheme.secondary,
          ),
        ),
      ),
    );
  }
}

but these are just the flutter widgets with set options for reusability

Technorocker
  • 103
  • 14

1 Answers1

-2

Wrap your SignUp class column with SingleChildScrollview after that wrap it up with Container which have property Like Below

Container(
    height: MediaQuery.of(context).size.height,
    width: MediaQuery.of(context).size.width,
    child:SingleChildScrollView(child:Column(your widgets))
)
  • unfortunately that still didnt work. The keyboard opens and the last field and signup button is in behind and the screen doesnt scroll at all. Im wondering if some sort of widget or dynamic element is "blocking" the singlechildscrollview from doing tis thing – Technorocker Apr 26 '22 at 13:31
  • https://www.veed.io/view/eb0aafe1-4ac7-4369-8213-1771c9aad350?sharingWidget=true See this video explanation – Gupta Akshay Apr 26 '22 at 13:52
  • No I understand what I'm trying to achieve. that video just shows the desired outcome I'm looking to have lol. Thanks though. And thats why I'm confused and showed my entire code. It doesnt make sense that every video or forum I see people just add the singlechild widget and it just works. I have tried over a dozens variances and my page wont scroll when the keyboard opens. As I mentioned I did try the scrolling on just the form fields but it still goes in behind the keyboard just that you can manually scroll it up( or down) – Technorocker Apr 26 '22 at 14:08
  • Can i have your entire code because there is some custom widget which is not included so i have replaced with simple widgets – Gupta Akshay Apr 26 '22 at 14:29
  • Thank you for looking into this. I have edited my post with the 2 widgets that are customized. I'm stumped cause this "seems" like a pretty straight forward screen. Nothing too fancy going on. lol – Technorocker Apr 27 '22 at 16:08