I am trying to create a scrollable sign up screen for when the keyboard pops up but my SingleChildScrollView widget doesn't seem to be working. I don't know whether this has to do with its placement in the stack or the inner column but help would be much appreciated. I've tried a ListView instead of a column, using the Expanded widget around the SingleChildScrollView but to no success.
An example to copy and run here.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SignUpScreen(),
);
}
}
class SignUpScreen extends StatefulWidget {
const SignUpScreen({Key? key}) : super(key: key);
@override
_SignUpScreenState createState() => _SignUpScreenState();
}
class _SignUpScreenState extends State<SignUpScreen> {
final _formKey = GlobalKey<FormState>();
bool _obscurePassword = true;
Color _obscureColor = Colors.grey;
InputDecoration textFormFieldDecoration = InputDecoration(
filled: true,
fillColor: const Color(0xFFF5F5F5),
prefixIcon: const Padding(
padding: EdgeInsets.symmetric(horizontal: 20),
child: Icon(
Icons.email,
color: Colors.blueAccent,
size: 26,
),
),
suffixIcon: null,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
borderSide: const BorderSide(color: Colors.white),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
borderSide: const BorderSide(color: Colors.white),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
borderSide: const BorderSide(color: Colors.white),
),
hintText: 'E-mail',
hintStyle: const TextStyle(
fontFamily: 'OpenSans',
fontSize: 18,
),
);
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
resizeToAvoidBottomInset: false,
// Shows circular progress indicator while loading
body:
// A stack lays items over one another.
Stack(
children: [
//The SizedBox provides the colored rounded aesthetic card behind the login.
SizedBox(
height: MediaQuery.of(context).size.height * 0.7,
child: Container(
color: Colors.redAccent,
),
),
Form(
key: _formKey,
child: Column(
// Keeps things in the center vertically
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// Builds App Logo
Row(
// Keeps things in the center horizontally.
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
'Heart',
style: TextStyle(
fontSize: 34,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
Text(
'by AHG',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
const SizedBox(height: 30),
// Build sign up container card.
ClipRRect(
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
child: SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height * 0.65,
width: MediaQuery.of(context).size.width * 0.85,
color: Colors.white,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
//Sign Up / Login Text
const Text(
'Sign Up',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.w700,
color: Colors.black,
),
),
const SizedBox(height: 25),
// Email form field
TextFormField(
keyboardType: TextInputType.emailAddress,
decoration: textFormFieldDecoration.copyWith(
prefixIcon: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 20),
child: Icon(
Icons.email,
color: Theme.of(context)
.colorScheme
.secondary,
size: 26,
),
),
hintText: 'E-mail'),
autocorrect: false,
),
const SizedBox(height: 13),
// Build password form field
TextFormField(
obscureText: _obscurePassword,
keyboardType: TextInputType.text,
decoration: textFormFieldDecoration.copyWith(
prefixIcon: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 20),
child: Icon(
Icons.lock,
color: Theme.of(context)
.colorScheme
.secondary,
size: 26,
),
),
suffixIcon: Padding(
padding: const EdgeInsets.only(right: 25),
child: IconButton(
icon: const Icon(
Icons.remove_red_eye_rounded),
color: _obscureColor,
iconSize: 23,
onPressed: () {
setState(() {
_obscurePassword =
!_obscurePassword;
_obscureColor == Colors.grey
? _obscureColor =
Theme.of(context)
.colorScheme
.secondary
: _obscureColor = Colors.grey;
});
},
),
),
hintText: 'Password'),
autocorrect: false,
),
const SizedBox(height: 13),
// Build confirm password form field
TextFormField(
obscureText: _obscurePassword,
keyboardType: TextInputType.text,
decoration: textFormFieldDecoration.copyWith(
prefixIcon: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 20),
child: Icon(
Icons.lock,
color: Theme.of(context)
.colorScheme
.secondary,
size: 26,
),
),
suffixIcon: Padding(
padding: const EdgeInsets.only(right: 25),
child: IconButton(
icon: const Icon(
Icons.remove_red_eye_rounded),
color: _obscureColor,
iconSize: 23,
onPressed: () {
setState(() {
_obscurePassword =
!_obscurePassword;
_obscureColor == Colors.grey
? _obscureColor =
Theme.of(context)
.colorScheme
.secondary
: _obscureColor = Colors.grey;
});
},
),
),
hintText: 'Confirm'),
autocorrect: false,
),
// Login Button
const SizedBox(
height: 30,
),
SizedBox(
height: 1.4 *
(MediaQuery.of(context).size.height / 20),
width: 5 *
(MediaQuery.of(context).size.width / 10),
child: ElevatedButton(
child: const Text('Sign Up'),
onPressed: _validateInputs,
),
),
],
),
),
),
),
),
//Sign Up Text
const SizedBox(
height: 20,
),
TextButton(
onPressed: () {},
child: RichText(
text: TextSpan(children: [
TextSpan(
text: 'Don\'t have an account?',
style: TextStyle(
color: Colors.black,
fontSize: MediaQuery.of(context).size.height / 40,
fontWeight: FontWeight.w400,
),
),
TextSpan(
text: ' Login',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
fontSize: MediaQuery.of(context).size.height / 40,
fontWeight: FontWeight.bold,
),
)
]),
),
),
],
),
)
],
),
),
);
}
void _validateInputs() {
if (_formKey.currentState?.validate() != null) {
final _validForm = _formKey.currentState!.validate();
if (_validForm) {
_formKey.currentState!.save();
}
}
}
}
CodePudding user response:
1)Change resizeToAvoidBottomInset to true 2)SingleChildScrollView put it before Stack
Like this
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
resizeToAvoidBottomInset: true,
// Shows circular progress indicator while loading
body:
// A stack lays items over one another.
SingleChildScrollView(
child: Stack(
children: [
CodePudding user response:
Put the SingleChildScrollView
as the Scaffold
's body.
Scaffold(
resizeToAvoidBottomInset: true,
body:
SingleChildScrollView(child: ...)
)