flutterflutter-dependenciesflutter-animationflutter-statetoggleswitch

Toggle switch animation not working in flutter


`I am trying to implement a toggle switch in which when I toggle the switch I display two different things but I'm getting an error while I use setstate with my logic or something like that if I remove the setstate from my code the animation starts working again but the logic does not work and I don't get two different outcomes when i toggle between the switch the code is :

import 'package:flutter/material.dart';
import 'package:sadapay_clone/screens/homepage.dart';
import 'package:sadapay_clone/widgets/physical_card_item.dart';
import 'package:sadapay_clone/widgets/virtual_card_item.dart';
import 'package:toggle_switch/toggle_switch.dart';

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

  @override
  State<CardScreen> createState() => _CardScreenState();
}

class _CardScreenState extends State<CardScreen>{
  // AnimationController _controller;

  bool toggle = false;

  // @override
  // void initState() {
  //   _controller = AnimationController(vsync: this);
  //   super.initState();
  // }

  // void toggleSwitch(int index) {
  //   if (index == 0) {
  //     setState(() {
  //       toggle = true;
  //     });
  //   } else if (index == 1) {
  //     setState(() {
  //       toggle = false;
  //     });
  //   }
  // }
  void toggleSwitch(int index) {
    if (index == 0) {
      setState(() {
        toggle = true;
      });
    } else if (index == 1) {
      setState(() {
        toggle = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          const SizedBox(height: 75),
          SizedBox(
            width: double.infinity,
            child: Row(
              // mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                IconButton(
                  onPressed: () {
                    Navigator.pop(
                      context,
                      MaterialPageRoute(
                        builder: (context) => const MyHomePage(),
                      ),
                    );
                  },
                  icon: const Icon(Icons.arrow_back_ios),
                ),
                Container(
                  width: 295,
                  alignment: Alignment.center,
                  child: const Text(
                    'My Cards',
                    style: TextStyle(
                      fontSize: 20,
                      fontWeight: FontWeight.w500,
                    ),
                    textAlign: TextAlign.center,
                  ),
                ),
              ],
            ),
          ),
          const SizedBox(
            height: 20,
          ),
          Container(
            alignment: Alignment.center,
            height: 40,
            width: 365,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(20),
              color: Colors.grey[300],
            ),
            child: ToggleSwitch(
              minHeight: 30,
              minWidth: 180.0,
              cornerRadius: 20.0,
              activeBgColors: const [
                [Colors.white],
                [Colors.white]
              ],
              activeFgColor: Colors.black,
              inactiveBgColor: Colors.grey[300],
              inactiveFgColor: Colors.black54,
              initialLabelIndex: 0,
              totalSwitches: 2,
              labels: const ['Virtual', 'Physical'],
              radiusStyle: true,
              onToggle: (index) {
                toggleSwitch(index!);
              },

              // onToggle: (index) {
              //   setState(() {
              //     toggle = index == 0;
              //   });
              // },
            ),
          ),
          toggle ? VirtualCard() : PhysicalCard(),
        ],
      ),
    );
  }
}

I tried using setstate logic inside the function rather than using it inside the onchanged property but still, the logic was working I was seeing two different outcomes when I pressed the switch but the animation was not working`


Solution

  • The issue is, while we are calling setState, the build method is trigger and setting initialLabelIndex to 0 again, you can do a check here,

    class _CardScreenState extends State<CardScreen> {
      bool toggle = false;
    
      void toggleSwitch(int index) {
        if (index == 0) {
          setState(() {
            toggle = true;
          });
        } else if (index == 1) {
          setState(() {
            toggle = false;
          });
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Column(
            children: [
              Container(
                alignment: Alignment.center,
                height: 40,
                width: 365,
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(20),
                  color: Colors.grey[300],
                ),
                child: ToggleSwitch(
                  minHeight: 30,
                  minWidth: 180.0,
                  cornerRadius: 20.0,
                  activeBgColors: const [
                    [Colors.white],
                    [Colors.white]
                  ],
                  activeFgColor: Colors.black,
                  inactiveBgColor: Colors.grey[300],
                  inactiveFgColor: Colors.black54,
                  initialLabelIndex: toggle ? 0 : 1,
                  totalSwitches: 2,
                  labels: ['Virtual', 'Physical'],
                  radiusStyle: true,
                  onToggle: (index) {
                    toggleSwitch(index!);
                  },
                ),
              ),
              toggle ? Text("VirtualCard") : Text("PhysicalCard"),
            ],
          ),
        );
      }
    }