Flutter - How to make a column screen scrollable
I'm building a flutter app with a Login Screen. On focus on the text field(s), the screen is overflowed and i cannot scroll. I've tried using a ListView.builder
, but that just gives a renderBox error, and the regular ListView
doesn't work
The widget structure is like this
-scafold
- body
- container
- column
- form
- column
- textInput
- textInput
- container
- container
- row
- raisedButton
Thank You in advance !!
The ListView
solution should work, but at the time of writing, it suffers from the crash listed here. Another way to achieve the same thing without this crash is to use a SingleChildScrollView
:
return new Container(
child: new SingleChildScrollView(
child: new Column(
children: <Widget>[
_showChild1(),
_showChild2(),
...
_showChildN()
]
)
)
);
try this Code: Its Using ListView
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
body: Center(
child: ListView(
shrinkWrap: true,
padding: EdgeInsets.all(15.0),
children: <Widget>[
Center(
child: Card(
elevation: 8.0,
child: Container(
padding: EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
TextField(
decoration: InputDecoration(
prefixIcon: Icon(Icons.person),
labelText: "Username or Email",
),
),
SizedBox(
height: 15.0,
),
TextField(
decoration: InputDecoration(
prefixIcon: Icon(Icons.lock),
labelText: "Password",
),
),
SizedBox(
height: 15.0,
),
Material(
borderRadius: BorderRadius.circular(30.0),
//elevation: 5.0,
child: MaterialButton(
onPressed: () => {},
minWidth: 150.0,
height: 50.0,
color: Color(0xFF179CDF),
child: Text(
"LOGIN",
style: TextStyle(
fontSize: 16.0,
color: Colors.white,
),
),
),
)
],
),
),
),
),
SizedBox(
height: 25.0,
),
Row(
children: <Widget>[
Expanded(child: Text("Don't Have a Account?")),
Text("Sign Up",
style: TextStyle(
color: Colors.blue,
)),
],
),
],
),
),
bottomNavigationBar: Padding(
padding: EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: RaisedButton(
padding: EdgeInsets.all(15.0),
onPressed: () {},
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
32.0,
),
side: BorderSide(color: Color(0xFF179CDF))),
child: Text(
"SKIP SIGN UP FOR NOW",
style:
TextStyle(fontSize: 18.0, color: Color(0xFF179CDF)),
),
)),
],
),
),
);
}
}
There are two easy ways of doing it.
-
Wrap your
Column
in aSingleChildScrollView
SingleChildScrollView( child: Column( children: [ Text('First'), //... other children Text('Last'), ], ), )
-
Use
ListView
instead ofColumn
.ListView( children: [ Text('First'), //... other children Text('Last'), ], )
This approach is simple to use, but you lose features like
crossAxisAlignment
and other benefits provided byColumn
, in that case, you can wrap your children widget insideAlign
and set alignment property.
Now you may have nested children which are further scrollable, in that case, you need to provide a fixed height to your children, you may use SizedBox
for that, that's it.
For example:
ListView(
children: [
Text('First'),
SizedBox(
height: 100,
child: ListView(...), // nested ScrollView
),
Text('Last'),
],
)
The column is used when we have to list widgets vertically on the screen and SingleChildScrollView
widget provides scroll functionality for Column
widgets.
When we used SingleChildScrollView+Column, the entire item list is rendered even if only a few items are visible.
So for complex layouts with a small number of items, the performance gain may not be worth the trouble, in which case we can use SingleChildScrollView.
Using SingleChildScrollView
with Columns
make your screen scrollable, and you can make your layout as above
Few Advantages:
- It will be useful when different widgets are needed with scroll functionality.
- For complex layouts, when items are less & performance, not a concern we can use it(Like when every other widget required some modification which is different from other)
Here is how can you do it
class MyHome extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
bottom: false,
child: Container(
padding: EdgeInsets.only(left: 15, right: 15),
height: double.infinity,
width: double.infinity,
child: SingleChildScrollView(
padding: EdgeInsets.only(bottom: 15),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 200.0,
),
Card(
elevation: 8.0,
child: Container(
padding: EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
TextField(
decoration: InputDecoration(
prefixIcon: Icon(Icons.person),
labelText: "Username or Email",
),
),
SizedBox(
height: 15.0,
),
TextField(
decoration: InputDecoration(
prefixIcon: Icon(Icons.lock),
labelText: "Password",
),
),
SizedBox(
height: 30.0,
),
MaterialButton(
height: 50.0,
elevation: 5,
minWidth: 300,
onPressed: () {},
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0),
),
color: Theme.of(context).primaryColor,
disabledColor: Theme.of(context)
.primaryColor
.withOpacity(0.50),
disabledElevation: 0,
child: Text('SIGN IN',
textAlign: TextAlign.center, style: TextStyle(color: Colors.white),))
],
),
),
),
SizedBox(
height: 25.0,
),
Row(
children: <Widget>[
Expanded(child: Text("Don't Have a Account?")),
Text("Sign Up",
style: TextStyle(
color: Colors.blue,
)),
],
),
SizedBox(
height: 50.0,
),
Align(
alignment: Alignment.bottomCenter,
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
Text(
'New to App?',
style: TextStyle(color: Colors.black87),
),
SizedBox(
width: 5,
),
GestureDetector(
onTap: () {
},
child: Text(
"REGISTER", style: TextStyle(
color: Colors.blue,
)
),
),
]),
)
],
)),
),
));
}
}