I have a requirement to develop a screen where there is collapsible content to be achieved using sliver.
However, the height of collapsible content is dynamic and depends on the number of dynamic widgets applicable to the user (some may not have both dynamic widgets, some have one, some have both). These dynamic widgets load as parallel service to backend and not in sequential manner. Otherwise I would have calculated the height one by one.
Help would be appreciated since all examples on internet point to have a fixed header height for slivers
Example image attached of what i am trying to achieve.
Try with the silver appbar and make sure that your toolbarHeight
is 0. Here I used just fixed height for a single element and the total height will be changed based on the number of elements or widgets you have.
import 'package:flutter/material.dart';
class DynamicAppbar extends StatefulWidget {
const DynamicAppbar({Key key}) : super(key: key);
@override
_DynamicAppbarState createState() => _DynamicAppbarState();
}
class _DynamicAppbarState extends State<DynamicAppbar> {
//set the height fixed for each widget
double fixedHeight = 50;
// replace with coming elements
List<String> items = [
"dynamicWidget1",
"dynamicWidget2",
"dynamicWidget3",
"dynamicWidget4",
];
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text("My App Bar"),
),
body: DefaultTabController(
length: 2,
child: NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
expandedHeight: fixedHeight * items.length,
floating: false,
pinned: true,
snap: false,
toolbarHeight: 0,
flexibleSpace: FlexibleSpaceBar(
background: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: List<Widget>.generate(
items.length,
(index) {
return Container(
height: fixedHeight,
child: Center(
child: Text(
items[index],
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 24, fontWeight: FontWeight.bold),
)),
);
},
),
),
),
),
SliverPersistentHeader(
delegate: _SliverAppBarDelegate(
TabBar(
labelColor: Colors.black87,
unselectedLabelColor: Colors.grey,
tabs: [
Tab(icon: Icon(Icons.info), text: "Tab 1"),
Tab(icon: Icon(Icons.lightbulb_outline), text: "Tab 2"),
],
),
),
pinned: true,
),
];
},
body: Center(
child: Text("Sample text"),
),
),
),
),
);
}
}
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
_SliverAppBarDelegate(this._tabBar);
final TabBar _tabBar;
@override
double get minExtent => _tabBar.preferredSize.height;
@override
double get maxExtent => _tabBar.preferredSize.height;
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return new Container(
child: _tabBar,
);
}
@override
bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
return false;
}
}
Output:
Before and after scrolling