I have done this using CustomScrollView and scroll_to_index plugin . here is code
class ScrollSample extends StatefulWidget {
const ScrollSample({Key? key}) : super(key: key);
@override
_ScrollSampleState createState() => _ScrollSampleState();
}
class _ScrollSampleState extends State<ScrollSample> {
late AutoScrollController _autoScrollController;
final scrollDirection = Axis.vertical;
bool isExpaned = true;
bool get _isAppBarExpanded {
return _autoScrollController.hasClients &&
_autoScrollController.offset > (160 - kToolbarHeight);
}
@override
void initState() {
_autoScrollController = AutoScrollController(
viewportBoundaryGetter: () =>
Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom),
axis: scrollDirection,
)..addListener(
() => _isAppBarExpanded
? isExpaned != false
? setState(
() {
isExpaned = false;
print('setState is called');
},
)
: {}
: isExpaned != true
? setState(() {
print('setState is called');
isExpaned = true;
})
: {},
);
super.initState();
}
Future _scrollToIndex(int index) async {
await _autoScrollController.scrollToIndex(index,
preferPosition: AutoScrollPosition.begin);
_autoScrollController.highlight(index);
}
Widget _wrapScrollTag({required int index, required Widget child}) {
return AutoScrollTag(
key: ValueKey(index),
controller: _autoScrollController,
index: index,
child: child,
highlightColor: Colors.black.withOpacity(0.1),
);
}
_buildSliverAppbar() {
return SliverAppBar(
brightness: Brightness.light,
pinned: true,
expandedHeight: 300.0,
backgroundColor: Colors.white,
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.parallax,
background: BackgroundSliverAppBar(),
),
bottom: PreferredSize(
preferredSize: Size.fromHeight(40),
child: AnimatedOpacity(
duration: Duration(milliseconds: 500),
opacity: isExpaned ? 0.0 : 1,
child: DefaultTabController(
length: 4,
child: TabBar(
onTap: (index) async {
_scrollToIndex(index);
},
tabs: [
Tab(
text: 'Amber',
),
Tab(
text: 'Green',
),
Tab(
text: 'Yellow',
),
Tab(
text: 'Red',
),
]),
),
),
),
);
}
Widget BackgroundSliverAppBar() {
return Stack(
children: <Widget>[
Positioned.fill(
child: Image.network(
"https://images.wallpapersden.com/image/download/colorful-neon-bubbles_a2dtaWmUmZqaraWkpJRmbmdlrWZlbWU.jpg",
fit: BoxFit.cover,
)),
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'Join as our member now,\nget discount upto 70%',
style: TextStyle(color: Colors.white),
),
SizedBox(height: 8.0),
RaisedButton(
child: Text(
'Subscribe now',
style: TextStyle(color: Colors.red),
),
onPressed: () {},
)
],
),
)
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: CustomScrollView(
controller: _autoScrollController,
slivers: <Widget>[
_buildSliverAppbar(),
SliverList(
delegate: SliverChildListDelegate([
_wrapScrollTag(
index: 0,
child: Container(
height: 300,
color: Colors.amber,
)),
_wrapScrollTag(
index: 1,
child: Container(
height: 700,
color: Colors.green,
)),
_wrapScrollTag(
index: 2,
child: Container(
height: 500,
color: Colors.yellow,
)),
_wrapScrollTag(
index: 3,
child: Container(
height: 500,
color: Colors.grey,
)),
])),
],
),
),
Container(
height: 40.0,
color: Colors.white,
)
],
),
);
}
}
all credit goes to Nhật Trần . take help from here