Search code examples
flutterflutter-animation

How to animate custom tab bar kind of widget?


So I have this widget that allows the user to select a tab from two or more tabs. This works fine in functionality but I want to animate it in such a way that when the user clicks on the other inactive tab, the white background slides to that tab instead of just appearing there instantly. Is there any way I can achieve this with the current code or do I need to update my code accordingly?

Here is the current code:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  MyApp({Key? key}) : super(key: key);

  final GlobalKey headerKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(home: HomePage());
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

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

class _HomePageState extends State<HomePage> {
  int active = 1;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('App bar')),
      body: Column(
        children: [
          const SizedBox(
            height: 20,
          ),
          const Text('Select one'),
          const SizedBox(
            height: 20,
          ),
          SelectOne(),
        ],
      ),
    );
  }
}

class SelectOne extends StatefulWidget {
  const SelectOne({super.key});

  @override
  State<SelectOne> createState() => _SelectOneState();
}

class _SelectOneState extends State<SelectOne> {
  // tab bar values
  final List<String> values = ['one', 'two'];

  // active value
  late String activeValue;

  @override
  void initState() {
    super.initState();

    // setting the active value
    activeValue = values[0];
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        color: Theme.of(context).primaryColor,
        borderRadius: BorderRadius.circular(100),
        border: Border.all(
          color: Theme.of(context).primaryColor,
          width: 2,
        ),
      ),
      child: Row(
          children: values.map(
        (value) {
          // whether the item is selected or not
          final bool isSelected = value == activeValue;

          return Expanded(
            child: GestureDetector(
              onTap: () {
                // setting the active value
                setState(() {
                  activeValue = value;
                });
              },
              child: Container(
                alignment: Alignment.center,
                padding: const EdgeInsets.all(6),
                decoration: BoxDecoration(
                  color: isSelected ? Colors.white : null,
                  borderRadius: BorderRadius.circular(100),
                ),
                child: Text(
                  value,
                  style: Theme.of(context).textTheme.bodyMedium!.copyWith(
                        fontWeight: isSelected ? FontWeight.w500 : null,
                        color: isSelected ? Colors.black : Colors.white,
                      ),
                ),
              ),
            ),
          );
        },
      ).toList()),
    );
  }
}

Here is the current output enter image description here


Solution

  • there is a widget named Tabbar is inbuild in flutter you should use that instead

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      MyApp({Key? key}) : super(key: key);
    
      final GlobalKey headerKey = GlobalKey();
    
      @override
      Widget build(BuildContext context) {
        return const MaterialApp(home: HomePage());
      }
    }
    
    class HomePage extends StatefulWidget {
      const HomePage({Key? key}) : super(key: key);
    
      @override
      State<HomePage> createState() => _HomePageState();
    }
    
    class _HomePageState extends State<HomePage> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: const Text('App bar')),
          body: Column(
            children: [
              const SizedBox(height: 20),
              const Text('Select one'),
              const SizedBox(height: 20),
              const SelectOne(),
            ],
          ),
        );
      }
    }
    
    class SelectOne extends StatefulWidget {
      const SelectOne({Key? key}) : super(key: key);
    
      @override
      State<SelectOne> createState() => _SelectOneState();
    }
    
    class _SelectOneState extends State<SelectOne> with SingleTickerProviderStateMixin {
      late TabController _tabController;
    
      @override
      void initState() {
        super.initState();
        _tabController = TabController(length: 2, vsync: this);
      }
    
      @override
      void dispose() {
        _tabController.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(
          decoration: BoxDecoration(
            color: Theme.of(context).primaryColor,
            borderRadius: BorderRadius.circular(100),
            border: Border.all(
              color: Theme.of(context).primaryColor,
              width: 2,
            ),
          ),
          child: TabBar(
            controller: _tabController,
            tabs: [
              Tab(text: 'one'),
              Tab(text: 'two'),
            ],
            labelStyle: Theme.of(context).textTheme.bodyMedium!.copyWith(
              fontWeight: FontWeight.w500,
              color: Colors.black,
            ),
            unselectedLabelStyle: Theme.of(context).textTheme.bodyMedium!.copyWith(
              fontWeight: null,
              color: Colors.white,
            ),
            indicator: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.circular(100),
            ),
            onTap: (index) {
              // Handle tab selection
            },
          ),
        );
      }
    }
    

    try this code i hope it helps you, if this helps then learn about tabbar widget and controller .