Skip to content

Instantly share code, notes, and snippets.

@kururu-abdo
Created November 23, 2025 09:36
Show Gist options
  • Select an option

  • Save kururu-abdo/9be512a93b6fad61c0e349c5244a5c6e to your computer and use it in GitHub Desktop.

Select an option

Save kururu-abdo/9be512a93b6fad61c0e349c5244a5c6e to your computer and use it in GitHub Desktop.
Scroll and update Tab bar
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
GlobalKey sectionOneKey = GlobalKey();
GlobalKey sectionTwoKey = GlobalKey();
GlobalKey sectionThreeKey = GlobalKey();
final ScrollController _scrollController = ScrollController();
@override
void initState() {
super.initState();
_scrollController.addListener(_onScroll);
}
int _selectedTab = 0;
void _onScroll() {
RenderBox renderBoxSectionOne = sectionOneKey.currentContext?.findRenderObject() as RenderBox;
RenderBox renderBoxSectionTwo = sectionTwoKey.currentContext?.findRenderObject() as RenderBox;
RenderBox renderBoxSectionThree = sectionThreeKey.currentContext?.findRenderObject() as RenderBox;
Offset positionSectionOne = renderBoxSectionOne.localToGlobal(Offset.zero);
Offset positionSectionTwo = renderBoxSectionTwo.localToGlobal(Offset.zero);
Offset positionSectionThree = renderBoxSectionThree.localToGlobal(Offset.zero);
// Repeat for other sections
// Example: Check if sectionOne is visible at the top
if (positionSectionOne.dy < MediaQuery.of(context).size.height / 2 && positionSectionOne.dy >= 0) {
// Update selected tab to section one
setState(() {
_selectedTab = 0; // Assuming 0 is the index for section one
});
}
if (positionSectionTwo.dy < MediaQuery.of(context).size.height / 2 && positionSectionTwo.dy >= 0) {
// Update selected tab to section one
setState(() {
_selectedTab = 1; // Assuming 0 is the index for section one
});
}
if (positionSectionThree.dy < MediaQuery.of(context).size.height / 2 && positionSectionThree.dy >= 0) {
// Update selected tab to section one
setState(() {
_selectedTab = 2; // Assuming 0 is the index for section one
});
}
// Add similar checks for other sections
}
@override
void dispose() {
_scrollController.removeListener(_onScroll);
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
home: Scaffold(
appBar: AppBar(
title:Row(
spacing: 8,
children: ['Section one', 'Section 2' , 'Section 3'].map((tab)=>
Column(
crossAxisAlignment: .start,
spacing: 5,
mainAxisSize: .min,
children: [
IntrinsicWidth(
child: Column(
children: [
Text(tab),
_selectedTab==['Section one', 'Section 2', 'Section 3'].indexOf(tab)?
Divider(
color:
_selectedTab==['Section one', 'Section 2'].indexOf(tab)?
Colors.amber: Colors.grey[500],
thickness: 5,
):
Divider(
color:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment