I tried to acheive from NestedScrollView by creating a sample code. But its not exactly which I want. Please help me. I want to achieve this ui. When scrolling appbar should dock at the top. Image top should start from status bar to the fixed height 300. After Image there would be some dynamic content like description. Then I have to add TabBar, which will dock just below the Appbar when scroll. Body will scroll on top of Header Image, like a overlay.
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class StickyTabbarExample extends StatefulWidget {
@override
_StickyTabbarExampleState createState() => _StickyTabbarExampleState();
}
class _StickyTabbarExampleState extends State<StickyTabbarExample>
with SingleTickerProviderStateMixin {
// TabController? _tabController;
final List<String> _tabs = <String>[
"Featured",
"Popular",
];
@override
void initState() {
super.initState();
// _tabController = TabController(vsync: this, length: _tabs.length);
}
@override
void dispose() {
// _tabController?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => Scaffold(
body: DefaultTabController(
length: _tabs.length,
child: NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) => <Widget>[
SliverAppBar(
pinned: true,
// floating: true,
toolbarHeight: 70,
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(
Icons.arrow_back_ios_new_sharp,
color: Colors.white,
size: 15,
),
Icon(
Icons.shop,
color: Colors.white,
size: 15,
)
]),
backgroundColor: Colors.green,
expandedHeight: 300,
flexibleSpace: FlexibleSpaceBar(
background: Image.network(
"https://images.unsplash.com/photo-1673942393203-fe61f45b4479?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=870&q=80%20870w",
fit: BoxFit.cover,
width: double.maxFinite,
),
),
),
SliverToBoxAdapter(
child: Positioned.fill(
child: Transform.translate(
offset: Offset(0, -10.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
height: 30,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.only(
topRight: Radius.circular(100),
topLeft: Radius.circular(100),
),
),
),
Text("Challenge description"),
],
),
),
),
),
SliverPersistentHeader(
delegate: _SliverAppBarDelegate(
TabBar(
indicator: UnderlineTabIndicator(
borderSide: BorderSide(
width: 4,
color: Color(0xFF646464),
),
insets: EdgeInsets.only(left: 0, right: 8, bottom: 4)),
isScrollable: true,
labelPadding: EdgeInsets.only(left: 0, right: 0),
tabs: [
Tab(
child: Text(
"Tab 1",
style: TextStyle(color: Colors.black),
),
),
Tab(
child: Text(
"Tab 2",
style: TextStyle(color: Colors.black),
)),
],
),
),
pinned: true,
),
],
body: TabBarView(children: [TabA(), TabB()]),
),
),
);
}
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) =>
Container(
color: Colors.white,
child: _tabBar,
);
@override
bool shouldRebuild(_SliverAppBarDelegate oldDelegate) => false;
}
class TabA extends StatelessWidget {
const TabA({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => CustomScrollView(
// primary: false,
key: PageStorageKey<String>("Tab1"),
slivers: [
SliverPadding(
padding: EdgeInsets.symmetric(vertical: 24, horizontal: 16),
sliver: SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) => Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
color: index % 2 == 0 ? Colors.green : Colors.greenAccent,
height: 80,
alignment: Alignment.center,
child: Text(
"Item $index",
style: const TextStyle(fontSize: 30),
),
),
),
// 40 list items
childCount: 40,
),
),
)
],
);
}
class TabB extends StatelessWidget {
const TabB({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => CustomScrollView(
key: PageStorageKey<String>("Tab2"),
slivers: [
SliverPadding(
padding: EdgeInsets.symmetric(vertical: 24, horizontal: 16),
sliver: SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) => Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
color: index % 2 == 0 ? Colors.green : Colors.greenAccent,
height: 80,
alignment: Alignment.center,
child: Text(
"Item $index",
style: const TextStyle(fontSize: 30),
),
),
),
childCount: 40,
),
),
)
],
);
}