Whenever, I switch from About to Recs or References tab my scroll position in the tab is maintained across all tabs. I want it to reset everytime I switch tabs. i.e Scrolling should start from top and not where I left in my previous tab before switching.
Here is my code:
// ignore_for_file: prefer_const_constructors
import 'package:flutter/material.dart';
class JobDetails extends StatefulWidget {
const JobDetails({Key? key}) : super(key: key);
@override
_JobDetailsState createState() => _JobDetailsState();
}
class _JobDetailsState extends State<JobDetails>
with SingleTickerProviderStateMixin {
late TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (context, isScrolled) {
return [
SliverPersistentHeader(
pinned: true,
delegate: MyHeaderDelegate(),
),
// SliverPadding(
// padding: EdgeInsets.symmetric(vertical: 26, horizontal: 18),
SliverPadding(
padding: EdgeInsets.symmetric(horizontal: 18),
sliver: SliverAppBar(
shape: ContinuousRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
),
automaticallyImplyLeading: false,
toolbarHeight: kTextTabBarHeight,
primary: false,
backgroundColor: Colors.grey[200],
pinned: true,
titleSpacing: 0,
title: TabBar(
indicator: BoxDecoration(
border: Border.all(
color: AppConstants.primaryColor,
),
borderRadius: BorderRadius.circular(7),
color: AppConstants.primaryColor),
unselectedLabelColor: const Color(0x66181D1A),
splashBorderRadius: BorderRadius.circular(7),
controller: _tabController,
//labelPadding: EdgeInsets.only(bottom: 20),
tabs: const [
Tab(
child: Text('About'),
),
Tab(text: 'Recs'),
Tab(text: 'References'),
],
),
),
),
];
},
body: TabBarView(
controller: _tabController,
children: [
SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Content for Tab 1
Padding(
padding: EdgeInsets.all(18.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Tab1')
],
),
),
],
),
),
SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
// Content for Tab 2
Padding(
padding: EdgeInsets.all(18.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 12,),
Text('Tab 2 Content'),
// Add your content for Tab 2 here
],
),
),
],
),
),
SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Content for Tab 3
Padding(
padding: EdgeInsets.all(18.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 12,),
Text('Tab3')
// Add your content for Tab 3 here
],
),
),
],
),
),
],
),
),
);
}
}
class MyHeaderDelegate extends SliverPersistentHeaderDelegate {
//delegate implementation
}
Tried using a scroll controller and resetting the state for every page change by adding a custom function after init, but did not work

The issue with your code is that all your
TabBarViewchildren are within the same class ofJobDetails, this causes all of the tabs to load during build time even when not selected.This is not the best practice because unnecessary code is executing even when the tab is not selected, and therefore your app could be slower during build time and can create unnecessary read/write to your database if you have any. Also there is no separate key that will reset the scroll of the widgets.
It would be better practice to load the
TabBarViewchildren only and only if the tab is selected by doing this:This would cause your scrolls to reset when switching Tabs because the children is being re-build (code executes) only after the specific tab is selected and the way to save the scroll position would be by using
key: const PageStorageKey<String>('key')in the scrollable widgetHowever if you're still insisting on doing it your way, then you need to add a
ScrollControllerand aListenerto listen for tab changes.Now add
controller: _scrollControllerin everySingleChildScrollView()widget.Keep in mind that the scroll of
NestedScrollView()widget could takeover theSingleChildScrollView()widget. If you are facing issues with that, you can either addcontroller: _scrollControllerto the NestedScrollView widget too or make it unscrollable by adding the parameter:physics: const NeverScrollableScrollPhysics(),