Technorocker
Technorocker

Reputation: 139

Flutter soft keyboard covering textfield and singlechildscrollview not working

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

Upvotes: 0

Views: 2138

Answers (1)

Gupta Akshay
Gupta Akshay

Reputation: 72

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))
)

Upvotes: -2

Related Questions