I am using slivers to display various kind of content. In some cases I have an empty title in AppBar and would like to push the content up to remove the blank space.
How would I do that?
This is my example:
class SliverPinnedExample extends StatelessWidget {
final List<String> items = List.generate(30, (i) => 'Item #$i');
@override
Widget build(BuildContext context) {
return Scaffold(
// Not using extendBodyBehindAppBar here, so the entire Scaffold won't shift up.
body: CustomScrollView(
slivers: [
SliverAppBar(
pinned: true,
// This ensures no geometry mismatch with pinned minHeight.
primary: true, // Tells Flutter to account for the status bar automatically.
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
// back nav
},
),
actions: [
IconButton(
icon: Icon(Icons.search),
onPressed: () {
// search
},
),
],
flexibleSpace: FlexibleSpaceBar(
background: Container(color: Colors.transparent),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
height: 60,
alignment: Alignment.centerLeft,
margin: EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Colors.grey.shade300),
),
),
child: Text(
items[index],
style: TextStyle(fontSize: 18),
),
);
},
childCount: items.length,
),
),
],
),
);
}
}
As you can see here the empty title with a blank space. I want to get the sliver list exactly above the AppBar. The list/content should begin at some point after below the statusbar.
In iOS you can adjust the paddings with contentInsets, but there is no option for that in flutter.
I am using slivers to display various kind of content. In some cases I have an empty title in AppBar and would like to push the content up to remove the blank space.
How would I do that?
This is my example:
class SliverPinnedExample extends StatelessWidget {
final List<String> items = List.generate(30, (i) => 'Item #$i');
@override
Widget build(BuildContext context) {
return Scaffold(
// Not using extendBodyBehindAppBar here, so the entire Scaffold won't shift up.
body: CustomScrollView(
slivers: [
SliverAppBar(
pinned: true,
// This ensures no geometry mismatch with pinned minHeight.
primary: true, // Tells Flutter to account for the status bar automatically.
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
// back nav
},
),
actions: [
IconButton(
icon: Icon(Icons.search),
onPressed: () {
// search
},
),
],
flexibleSpace: FlexibleSpaceBar(
background: Container(color: Colors.transparent),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
height: 60,
alignment: Alignment.centerLeft,
margin: EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Colors.grey.shade300),
),
),
child: Text(
items[index],
style: TextStyle(fontSize: 18),
),
);
},
childCount: items.length,
),
),
],
),
);
}
}
As you can see here the empty title with a blank space. I want to get the sliver list exactly above the AppBar. The list/content should begin at some point after below the statusbar.
In iOS you can adjust the paddings with contentInsets, but there is no option for that in flutter.
I already tried your code, and everything appears fine; there's no extra space between the SliverAppBar
and SliverList
. I'm not sure if this issue is device-specific.
However, you could try defining toolbarHeight
in the SliverAppBar
.
As I understand from you question:
You have a widget consisting of a List
of items and a SliverAppBar
.
If the title
of this widget is empty the initial position of the List
is under the AppBar
And if the title is not empty the initial position of the scrolling is normal position
In Flutter, you can easily handle this behavior using the initialScrollOffset
property of a ScrollController
.
Demo video of the provided solution: initial_scroll_position
Define the controller
and initialize it in the initState
and define the itemHeight
property , also create a helper method to check if the title is empty of not
late final ScrollController _controller;
double itemHeight = 60.0;
bool get isTitleEmpty => widget.title.isEmpty;
@override
void initState() {
_controller = ScrollController(
initialScrollOffset: isTitleEmpty ? itemHeight : 0.0,
);
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
final List<String> items = List.generate(30, (i) => 'Item #$i');
If the title is empty, the initialScrollOffset
is set to the height of one list item (itemHeight
). This ensures the list starts under the AppBar
.
If the title is not empty, the initialScrollOffset
is set to 0.0
, which is the default starting position.
class SliverPinnedExample extends StatefulWidget {
const SliverPinnedExample({
super.key,
required this.title,
});
final String title;
@override
State<SliverPinnedExample> createState() => _SliverPinnedExampleState();
}
class _SliverPinnedExampleState extends State<SliverPinnedExample> {
late final ScrollController _controller;
double itemHeight = 60.0;
bool get isTitleEmpty => widget.title.isEmpty;
@override
void initState() {
_controller = ScrollController(
initialScrollOffset: isTitleEmpty ? itemHeight : 0.0,
);
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
final List<String> items = List.generate(30, (i) => 'Item #$i');
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
controller: _controller,
slivers: <Widget>[
SliverAppBar(
pinned: true,
primary: true,
backgroundColor: Colors.transparent,
elevation: 0,
title: isTitleEmpty ? null : Text(widget.title),
actions: [
IconButton(
icon: const Icon(Icons.search),
onPressed: () {
// search
},
),
],
flexibleSpace: FlexibleSpaceBar(
background: Container(color: Colors.transparent),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
height: itemHeight,
alignment: Alignment.centerLeft,
margin: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Colors.grey.shade300),
),
),
child: Text(
items[index],
style: const TextStyle(fontSize: 18),
),
);
},
childCount: items.length,
),
),
],
),
);
}
}
Hope that was helpful !
AppBar
..... 1. do you want theAppBar
to be visible or just the item be under it ? ....2. what is the conditions is required to achieve this scroll ? , just when the title is empty or what ? .....3. do you want this as the initial state of the scrolling or it is persistence ? – Mahmoud Al-shehyby Commented Mar 10 at 21:50