How to do animated switcher with slivers in flutter - flutter

So I have a CustomScrollView with a SliverAppBar(floating: true, snap: true), a SliverPersistentHeader(pinned: true) a SliverList.
What I am trying to do is to click a button in the header and just pop a widget in the space taken by the SliverPersistentHeade and SliverList. I tried putting them inside a nestedScrollView and nesting SliverPersistentHeader and SliverList inside another scrollView but since the SliverAppBar and SliverPersistentHeader are not together it messes up the supposed effect when it(SliverAppBar) snaps up and off.
Why do I need it like that: I want to perform some animations with the elements in the appBar as the lower part transitions between the two pages kinda like animtions shared axis package
problems
keep the persistantHeader on the first page
keep the snap floating appbar feature
transition the lower part
Note: Answers don't necessary need to depend on slivers. a possible way to achieve that will do
My code at the moment looks roughly like this
CustomScrollView(
physics: BouncingScrollPhysics(),
slivers: [
SliverAppBar(
backgroundColor: Colors.white,
floating: true,
snap: true,
titleSpacing: 0,
elevation: 4,
title: Row(
children: [
Expanded(
child: Container(
padding: EdgeInsets.only(top: 10, bottom: 10, left: 10),
child: Container(color: Colors.grey),
),
),
),
Container(
child: LeadingButton(
color: lightShadeColor,
icon: Icons.qr_code_scanner_rounded,
iconColor: darkColor,
size: 37, // btnShadow: false
),
),
],
),
),
SliverPersistentHeader(
delegate: PersistentHeader(
widget: Row(
// Format this to meet your need
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
padding: EdgeInsets.all(10),
child: Text('data'),
)
],
),
),
pinned: true,
),
SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
return ListTile(
title: Text('index $index'),
);
}),
)
],
),

Related

How to fix Column overflow in NestedScrollView body?

So basically I am using a NestedScrollView with a column body that holds a TabBar and TabBarView:
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
physics: BouncingScrollPhysics(),
headerSliverBuilder: (context, innerScrolled) {
return [
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
sliver: SliverAppBar(
stretch: true,
pinned: true,
collapsedHeight: 400,
backgroundColor: Colors.red,
),
),
SliverList(
delegate: SliverChildListDelegate(
[
SizedBox(height: 20),
Biography(),
SizedBox(height: 20),
],
),
),
];
},
body: Column(
children: [
Container(
child: TabBar(
controller: this.controller,
tabs: [
Tab(icon: Icon(CupertinoIcons.book)),
Tab(icon: Icon(CupertinoIcons.music_albums)),
],
),
),
Expanded(
child: TabBarView(
controller: this.controller,
children: [
// this is in reality a customscrollview
Container(color: Colors.red),
// this is in reality a customscrollview
Container(color: Colors.blue),
],
),
),
],
),
),
);
}
The error:
When I scroll up, i.e my thumb is going toward the bottom of the screen, and the Container that is in the Column reaches the bottom of the screen, it causes an overflow error. The Expanded TabBarView is fine, it's the Container that causes the overflow.
What I've tried:
I've tried to change the Column to a ListView as stated here but it results in another error(something about hasSize). I did set shrinkWrap: true.
Use Expanded on the Container but it results in a wonky UI.
Wrapping the Column in a SingleChildScrollView but it also results in the same error as ListView.
How can I make it so the Container doesn't cause an overflow when it reaches the bottom of the screen?
Thank you!

Flutter: ReorderableListView within CustomScrollView

I have this design:
CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
const SliverAppBar(
pinned: true,
expandedHeight: 250.0,
flexibleSpace: FlexibleSpaceBar(
title: Text('Demo'),
),
),
SliverList(
delegate: SliverChildListDelegate(
[
Text("sds"),
],
),
),
SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 4.0,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
color: Colors.teal[100 * (index % 9)],
child: Text('Grid Item $index'),
);
},
childCount: 10,
),
),
SliverFillRemaining(
child: ReorderableListView(
scrollController: _scrollController,
children: <Widget>[
for (final items in item)
Card(
color: Colors.blueGrey,
key: ValueKey(items),
elevation: 2,
child: ListTile(
title: Text(items),
leading: Icon(
Icons.work,
color: Colors.black,
),
),
),
],
onReorder: reorderData,
),
),
],
),
Everything between the SliverAppBar and the ReorderableListView is just an example of how it should work.
I need to order some elements so for that I use a ReorderableListView but this needs to be inside a CustomScrollView and using its scroll. Right now everything works except for the scroll. The SliverAppBar minimises when scrolling over the grid, but the ReorderableListView has it owns scroll.
Is there any way to cancel the second scroll and having these 2 elements working together?
I also uses this library https://pub.dev/packages/reorderables but if you have a look to the repo it seems abandoned (and I faced different issues)

Manage two Listview, to keep the first one showing when the user wants to scroll down to view the second listview items, Flutter

may i ask how to force the first Horizontal Listview Showing when i scroll the another Vertical Listview.
This is My Screen
when i scrolling Down to view the Vertical Listview, the Second one to view the items. Then this happens
So the user can't see the First Horizontal ListView any more , he must to go up to view it.
and this is my problem, i want that the Horizontal Listview to keep showing when the user scrolled the Vertical Listview Items down.
Thanks in Advance.
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Container(
child: ListView(
shrinkWrap: true,
children: [
Container(
color: Colors.white,
margin: EdgeInsets.symmetric(vertical: 20.0),
height: 200.0,
child: ListView(... ), // Horizontal ListView
),
Expanded(
child: Container(
child: ParseLocal(), // Vertical ListView
),
),
],
),
),
),
You don't need to wrap two widget with ListView since your two widgets is ListView.
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Container(
child: ListView( // <--this can be removed
shrinkWrap: true,
children: [
Container(
color: Colors.white,
margin: EdgeInsets.symmetric(vertical: 20.0),
height: 200.0,
child: ListView(... ), // Horizontal ListView
),
Expanded(
child: Container(
child: ParseLocal(), // Vertical ListView
),
),
],
),
),
),

How to scroll individual page when we use tabbar in flutter?

I want to make scrollable page in flutter when we use Tabbar in flutter.
I tried this code but this is not working.
In this code my whole listview I cannot see. How to display whole listview items while using tabbar.
So, how can I solve this problem.
Widget _listofitem() {
return Container(
margin: EdgeInsets.only(top: 10.0),
padding: EdgeInsets.all(8.0),
child: ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: categoryDetail.length,
itemBuilder: (BuildContext context, int index) {
return Container(
padding: EdgeInsets.all(8.0),
width: MediaQuery.of(context).size.width,
height: 100.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: Colors.cyanAccent),
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: SizedBox(
height: 20,
width: 20,
// child: NetworkImage(categoryDetail[index]),
),
),
SizedBox(
height: 10.0,
),
Text(categoryDetail[index]['category_name'].toString()),
],
),
);
},
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(
'Invitation Card Application',
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.cyan,
centerTitle: true,
bottom: TabBar(
tabs: myTabs,
controller: _tabController,
)
),
body: TabBarView(
controller: _tabController,
children: myTabs.map((Tab tab) {
return Center(
child: Stack(
children: <Widget>[
_listofitem(),
// _ofitem()
],
),
);
}).toList(),
));
}
I want to change page on individual tab click and also do scroll in that individual page. So I display whole my page. What is the solution for it.
In the ListView.builder() widget you have set the property,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
This is preventing the scroll on the list view. If you want to wrap the list view inside the container with the above properties, then wrap the container in the SingleChildScrollView widget.
SingleChildScrollView(
child: Container(),
);
By this, you can have the scroll effect and you will be able to see all the list view items

How to vertically center text/title in Flutter using SliverAppBar?

I am trying to set up a SliverAppBar in a CustomScrollView using Flutter, and can't get to vertically center the title.
I already tried this solution (and this SO question is exactly what I want to do) but fortunately, it didn't work for me.
Here is my build method:
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: true,
expandedHeight: 200,
//backgroundColor: Colors.transparent,
flexibleSpace: FlexibleSpaceBar(
titlePadding: EdgeInsets.zero,
centerTitle: true,
title: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text("Should be centered", textAlign: TextAlign.center),
],
),
background: Image.asset("assets/earth.jpg", fit: BoxFit.cover),
),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.menu),
tooltip: "Menu",
onPressed: () {
// onPressed handler
},
),
],
),
SliverFixedExtentList(
itemExtent: 50,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
color: Colors.green,
child: Text("Index n°$index"),
);
},
),
)
],
),
);
}
I really don't understand what is wrong and why it isn't centered. I observed that the column is way too big when setting mainAxisSize to mainAxisSize.max.
Any idea?
Thanks in advance!
I tinkered around a bit in your code and was able to center it. So the main problem here was the expandedHeight. This height expands the SliverAppBar both upwards and downwards meaning that half of that 200 was always above the screen. Taking that into consideration, you would be trying to center the text in only the bottom half of the app bar. The simplest way was to just use Flexible to size the items relative to their container. Here's the working code:
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: true,
expandedHeight: 200,
//backgroundColor: Colors.transparent,
flexibleSpace: FlexibleSpaceBar(
titlePadding: EdgeInsets.zero,
centerTitle: true,
title: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
flex: 3,
child: Container(),
),
Flexible(
flex: 1,
child:
Text("Should be centered", textAlign: TextAlign.center),
),
Flexible(
flex: 1,
child: Container(),
),
],
),
background: Image.asset("assets/earth.png", fit: BoxFit.cover),
),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.menu),
tooltip: "Menu",
onPressed: () {
// onPressed handler
},
),
],
),
SliverFixedExtentList(
itemExtent: 50,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
color: Colors.green,
child: Text("Index n°$index"),
);
},
),
)
],
),
);
}
A way without empty containers
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: true,
expandedHeight: 200,
flexibleSpace: FlexibleSpaceBar(
titlePadding: EdgeInsets.zero,
centerTitle: true,
title: SizedBox(
height: 130,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Should be centered", textAlign: TextAlign.center),
],
),
),
background: Image.asset("assets/earth.png", fit: BoxFit.cover),
),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.menu),
tooltip: "Menu",
onPressed: () {
// onPressed handler
},
),
],
),
SliverFixedExtentList(
itemExtent: 50,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
alignment: Alignment.center,
color: Colors.green,
child: Text("Index n°$index"),
);
},
),
)
],
),
);
}
Instead of using a FlexibleSpaceBar use a different Widget.
flexibleSpace: Padding(
padding: EdgeInsets.all(4),
child: Container(),
}),
),
Kinda like what Pedro said earlier, you can instead use the flexibleSpace parameter in SliverAppBar, and then center things from there. This is what I did.
SliverAppBar(
flexibleSpace: Center(
child: Text("27 is my favorite number")
)
)