How to use Expanded in SingleChildScrollView?
Solution 1:
Instead of using SingleChildScrollView
, It's easier to use CustomScrollView
with a SliverFillRemaining
.
Try this:
CustomScrollView(
slivers: [
SliverFillRemaining(
hasScrollBody: false,
child: Column(
children: <Widget>[
const Text('Header'),
Expanded(child: Container(color: Colors.red)),
const Text('Footer'),
],
),
),
],
)
Solution 2:
Try this,
LayoutBuilder(
builder: (context, constraint) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraint.maxHeight),
child: IntrinsicHeight(
child: Column(
children: <Widget>[
Text("Header"),
Expanded(
child: Container(
color: Colors.red,
),
),
Text("Footer"),
],
),
),
),
);
},
)
I got this solution from git issues when I get into the same situation. I don't have the git link. I think it may help you.
Reusable widget:
Note: use it, only if one of the children is Expanded
import 'package:flutter/material.dart';
class ScrollColumnExpandable extends StatelessWidget {
final List<Widget> children;
final CrossAxisAlignment crossAxisAlignment;
final MainAxisAlignment mainAxisAlignment;
final VerticalDirection verticalDirection;
final TextDirection textDirection;
final TextBaseline textBaseline;
final EdgeInsetsGeometry padding;
const ScrollColumnExpandable({
Key key,
this.children,
CrossAxisAlignment crossAxisAlignment,
MainAxisAlignment mainAxisAlignment,
VerticalDirection verticalDirection,
EdgeInsetsGeometry padding,
this.textDirection,
this.textBaseline,
}) : crossAxisAlignment = crossAxisAlignment ?? CrossAxisAlignment.center,
mainAxisAlignment = mainAxisAlignment ?? MainAxisAlignment.start,
verticalDirection = verticalDirection ?? VerticalDirection.down,
padding = padding ?? EdgeInsets.zero,
super(key: key);
@override
Widget build(BuildContext context) {
final children = <Widget>[const SizedBox(width: double.infinity)];
if (this.children != null) children.addAll(this.children);
return LayoutBuilder(
builder: (context, constraint) {
return SingleChildScrollView(
child: Padding(
padding: padding,
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraint.maxHeight - padding.vertical,
),
child: IntrinsicHeight(
child: Column(
crossAxisAlignment: crossAxisAlignment,
mainAxisAlignment: mainAxisAlignment,
mainAxisSize: MainAxisSize.max,
verticalDirection: verticalDirection,
children: children,
textBaseline: textBaseline,
textDirection: textDirection,
),
),
),
),
);
},
);
}
}
Solution 3:
The answer is in the error itself. When the column is inside a view that is scrollable, the column is trying to shrink-wrap its content but since you used Expanded
as a child of the column it is working opposite to the column trying to shrink-wrap its children. This is causing this error because these two directives are completely opposite to each other.
As mentioned in the error logs try the following:
Consider setting mainAxisSize
to MainAxisSize.min
(for column) and using FlexFit.loose
fits for the flexible(use Flexible
rather than Expanded
).
Solution 4:
I tried Vijaya Ragavan solution but did some adjustments to it & it still works.
To use Expanded
with SingleChildScrollView
, I used ConstrainedBox
and set its height to the height of the screen (using MediaQuery
). You'll just need to make sure the screen content you put inside ConstrainedBox
is not bigger than the height of the screen.
Otherwise set the height of ConstrainedBox
to height of the content you want to display on the screen.
SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Text('Hello World!'),
),
],
),
)
)
Edit:
To subtract the height of the AppBar
and/or the Status Bar, see below:
double screenHeightMinusAppBarMinusStatusBar = MediaQuery.of(context).size.height
- appBar.preferredSize.height
- MediaQuery.of(context).padding.top;
Solution 5:
Simply wrap your SingleChildScrollView
in a Center
or an Align
element.
Example :
Align(
alignment: Alignment.topCenter,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
...
]
}
}
}
or
Center(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
...
]
}
}
}