I know with a ListView
or SingleChildScrollView
RefreshIndicator
just works natively but I want to use a RefreshIndicator
You must do the following:
SingleChildScrollView
with the property physics
set to AlwaysScrollableScrollPhysics()
.MediaQuery.of(context).size.height
.The complete example:
classs MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RefreshIndicator(
onRefresh: () {},
child: SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: Container(
child: Center(
child: Text('Hello World'),
),
height: MediaQuery.of(context).size.height,
),
),
);
}
}
Most of the other answers will work but they all have some downsides. Using a SingleChildScrollView
without adjusting the height will cause the "scrolling glowing effect" to be not at the bottom of the page. Setting the height to the maximum height of the current view (by using MediaQuery
or a LayoutBuilder
) will solve this problem, but there will be a render overflow when your content's height is bigger than the height of the available space.
At the end, the following solution worked perfectly for me without any problems:
LayoutBuilder(
builder: (context, constraints) => RefreshIndicator(
onRefresh: _refresh,
child: SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: constraints.maxHeight
),
child: Text("Your Widget")
)
)
),
)
Complementing Gustavo answer you can use constraints to define the minimum size of SingleChildScrollView in this way
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RefreshIndicator(
onRefresh: () {},
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.height,
),
child: SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: Center(
child: Text('Hello World'),
),
),
),
);
}
}
So in my case I wanted to display a placeholder in an empty list:
RefreshIndicator(
child: Stack(
children: <Widget>[
Center(
child: Text("The list is empty"),
),
ListView()
],
),
onRefresh: () {},
)
More flexible solution is put your scrollable empty/error state widget into LayoutBuilder
LayoutBuilder(
builder: (context, constraints) => SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: SizedBox(
height: constraints.maxHeight,
child: ErrorState(
subtitle: (snapshot.data as ErrorStateful).errorMessage),
),
),
);
Is it possible without page that doesn't scroll?
-No.
Please read the documentation of the parameter child in RefreshIndicator:
The widget below this widget in the tree.
The refresh indicator will be stacked on top of this child. The indicator will appear when child's Scrollable descendant is over-scrolled.
Typically a [ListView] or [CustomScrollView].
Is there a work-around?
-Yes
You can put only one widget in the Listview's children list:
new RefreshIndicator(
child: new ListView(
children: <Widget>[
new Text('This is child with refresh indicator'),
],
),
onRefresh: () {},
)