import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
double scrollOffset = 0;
double maxScrollExtent = 0;
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 20,
child: Scaffold(
appBar: AppBar(
bottom: PreferredSize(
preferredSize: const Size.fromHeight(56.0),
child: NotificationListener<ScrollMetricsNotification>(
onNotification: (ScrollMetricsNotification notification) {
setState(() {
scrollOffset = notification.metrics.pixels;
maxScrollExtent = notification.metrics.maxScrollExtent;
});
return false;
},
child: Stack(
children: [
TabBar(
isScrollable: true,
tabs: List<Widget>.generate(
20,
(int index) => Tab(text: 'Tab $index'),
),
),
// When the tab list is not the begining or end (indicating tabbar is scrollable),
// add gradient mask to left or right.
// Left mask: shows when NOT at the beginning.
if (scrollOffset > 0)
Positioned(
left: 0,
top: 0,
bottom: 0,
width: 50,
child: IgnorePointer(
child: ClipRect(
child: BackdropFilter(
filter: ColorFilter.mode(
Colors.black.withValues(alpha: 0.05),
BlendMode.srcOver,
),
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [
Colors.white.withValues(alpha: 0.8),
Colors.white.withValues(alpha: 0.0),
],
),
),
child: const Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.only(left: 4),
child: Icon(
Icons.chevron_left,
color: Colors.black54,
),
),
),
),
),
),
),
),
// Right mask: shows when NOT at the end
if (scrollOffset < maxScrollExtent)
Positioned(
right: 0,
top: 0,
bottom: 0,
width: 50,
child: IgnorePointer(
child: ClipRect(
child: BackdropFilter(
filter: ColorFilter.mode(
Colors.black.withValues(alpha: 0.05),
BlendMode.srcOver,
),
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerRight,
end: Alignment.centerLeft,
colors: [
Colors.white.withValues(alpha: 0.8),
Colors.white.withValues(alpha: 0.0),
],
),
),
child: const Align(
alignment: Alignment.centerRight,
child: Padding(
padding: EdgeInsets.only(right: 4),
child: Icon(
Icons.chevron_right,
color: Colors.black54,
),
),
),
),
),
),
),
),
],
),
),
),
),
),
);
}
}Demo:
