smooth_infinite_tab_bar 0.0.3 copy "smooth_infinite_tab_bar: ^0.0.3" to clipboard
smooth_infinite_tab_bar: ^0.0.3 copied to clipboard

A horizontally scrolling tab bar with infinite bidirectional items. Smooth animations, auto-scroll on selection, and fully customizable. Zero dependencies beyond Flutter SDK.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:smooth_infinite_tab_bar/smooth_infinite_tab_bar.dart';

void main() => runApp(const ExampleApp());

class ExampleApp extends StatelessWidget {
  const ExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'smooth_infinite_tab_bar example',
      theme: ThemeData.light(useMaterial3: true),
      darkTheme: ThemeData.dark(useMaterial3: true),
      home: const _HomePage(),
    );
  }
}

class _HomePage extends StatefulWidget {
  const _HomePage();

  @override
  State<_HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<_HomePage> {
  // ── Example 1: Month selector ─────────────────────────────────────

  int _monthIndex = 0;

  DateTime _monthAt(int i) {
    final now = DateTime.now();
    // Handle month overflow correctly via DateTime constructor
    return DateTime(now.year, now.month + i, 1);
  }

  static const _months = [
    'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
    'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',
  ];

  String _monthLabel(int i) => _months[_monthAt(i).month - 1];

  String? _yearLabel(int i) {
    final d = _monthAt(i);
    return d.year != DateTime.now().year ? '${d.year}' : null;
  }

  // ── Example 2: Week selector ────────────────────────────────────

  int _weekIndex = 0;

  DateTime _weekStart(int i) {
    final now = DateTime.now();
    final monday = now.subtract(Duration(days: now.weekday - 1));
    return monday.add(Duration(days: 7 * i));
  }

  String _weekLabel(int i) => 'W${_isoWeek(_weekStart(i))}';

  String? _weekSubLabel(int i) {
    final d = _weekStart(i);
    return '${_months[d.month - 1]} ${d.day}';
  }

  static int _isoWeek(DateTime date) {
    final doy = date.difference(DateTime(date.year, 1, 1)).inDays + 1;
    return ((doy - date.weekday + 10) / 7).floor();
  }

  // ── Example 3: Generic category tab (finite) ───────────────────

  int _catIndex = 0;
  static const _cats = [
    'All', 'Food', 'Rent', 'Transport', 'Health', 'Leisure', 'Savings',
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('smooth_infinite_tab_bar')),
      body: ListView(
        children: [
          const SizedBox(height: 24),

          // ── Month selector (truly infinite) ───────────────
          _SectionLabel('Month selector (infinite)'),
          InfiniteTabBar(
            selectedIndex: _monthIndex,
            labelBuilder: _monthLabel,
            sublabelBuilder: _yearLabel,
            isHighlighted: (i) => i == 0,
            onSelected: (i) => setState(() => _monthIndex = i),
            // No hard limit — scroll infinitely in both directions
            shouldAddBottom: (_) => true,
            shouldAddTop: (_) => true,
          ),
          _SectionContent(
            'Selected: ${_monthLabel(_monthIndex)}'
            ' ${_monthAt(_monthIndex).year}',
          ),

          const SizedBox(height: 32),

          // ── Week selector ──────────────────────────────────
          _SectionLabel('Week selector'),
          InfiniteTabBar(
            selectedIndex: _weekIndex,
            labelBuilder: _weekLabel,
            sublabelBuilder: _weekSubLabel,
            isHighlighted: (i) => i == 0,
            itemWidth: 80,
            onSelected: (i) => setState(() => _weekIndex = i),
            shouldAddBottom: (_) => true,
            shouldAddTop: (_) => true,
          ),
          _SectionContent(
            'Week of ${_weekStart(_weekIndex).day}/'
            '${_weekStart(_weekIndex).month}/'
            '${_weekStart(_weekIndex).year}',
          ),

          const SizedBox(height: 32),

          // ── Category tabs (finite bounded list) ───────────
          _SectionLabel('Category tabs (finite)'),
          InfiniteTabBar(
            selectedIndex: _catIndex,
            labelBuilder: (i) =>
                i >= 0 && i < _cats.length ? _cats[i] : '',
            itemWidth: 110,
            onSelected: (i) => setState(() => _catIndex = i),
            shouldAddBottom: (i) => i < _cats.length,
            shouldAddTop: (_) => false,
          ),
          _SectionContent('Category: ${_cats[_catIndex]}'),

          const SizedBox(height: 40),
        ],
      ),
    );
  }
}

class _SectionLabel extends StatelessWidget {
  const _SectionLabel(this.text);
  final String text;

  @override
  Widget build(BuildContext context) => Padding(
        padding: const EdgeInsets.only(left: 16, bottom: 8),
        child: Text(text,
            style: const TextStyle(
                fontSize: 16, fontWeight: FontWeight.bold)),
      );
}

class _SectionContent extends StatelessWidget {
  const _SectionContent(this.text);
  final String text;

  @override
  Widget build(BuildContext context) => Padding(
        padding: const EdgeInsets.only(left: 16, top: 8),
        child: Text(text,
            style: TextStyle(
                color: Theme.of(context).colorScheme.secondary)),
      );
}
1
likes
160
points
178
downloads

Documentation

API reference

Publisher

verified publishereliazavatta.it

Weekly Downloads

A horizontally scrolling tab bar with infinite bidirectional items. Smooth animations, auto-scroll on selection, and fully customizable. Zero dependencies beyond Flutter SDK.

Repository (GitHub)
View/report issues

Topics

#tab-bar #infinite-scroll #animations #ui #smooth

License

MIT (license)

Dependencies

flutter

More

Packages that depend on smooth_infinite_tab_bar