flutterdartuser-interfacefloating-action-buttoniconbutton

How to toggle between play and pause icons in Flutter button?


I have a FloatingActionButton that changes its icon to a pause icon when clicked. How can I toggle the icon back to the play icon when the button is clicked again?

Code:

Row(
  mainAxisAlignment: MainAxisAlignment.center,
    crossAxisAlignment: CrossAxisAlignment.center,
    children: [
      AnimatedBuilder(
          animation: controller,
          builder: (context, child) {
            return FloatingActionButton.extended(
                onPressed: () {
                  if (controller.isAnimating)
                    controller.stop();
                  else {
                    controller.reverse(
                        from: controller.value == 0.0
                            ? 1.0
                            : controller.value);
                  }
            },
                icon: Icon(
                  controller.isAnimating
                    ? Icons.pause
                    : Icons.play_arrow  ,
                  color: Color(0xffF2F2F2),),

                label: Text(
                  controller.isAnimating ? "Pause" : "Play",));

          }),
      SizedBox(width: 20,),
      AnimatedBuilder(
          animation: controller,
          builder: (context, child) {
            return FloatingActionButton.extended(
              onPressed: () {
                if (controller.isAnimating)
                  controller.reset();
              },
              icon: Icon(Icons.refresh,
                color: Color(0xffF2F2F2),),

              label: Text("Refresh",),);

          }),
    ],
  )

Explanation:

I want to be able to switch seamlessly between a play icon (Icons.play_arrow) and a pause icon (Icons.pause) on my button with each click.


Solution

  • Create a variable _isPlaying = false and then update it accordingly. Additionally, call myController.forward() instead of reverse(). I'm no master of animations, so I might of gotten this wrong (you might have to tweak this a bit). But it does seem to work:

    import 'package:flutter/material.dart';
    
    const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          theme: ThemeData.dark().copyWith(
            scaffoldBackgroundColor: darkBlue,
          ),
          debugShowCheckedModeBanner: false,
          home: Scaffold(
            body: Center(
              child: MyWidget(),
            ),
          ),
        );
      }
    }
    
    class MyWidget extends StatelessWidget {
      MyWidget({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({Key? key, required this.title}) : super(key: key);
    
      final String title;
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage>
        with SingleTickerProviderStateMixin {
      var _animationController;
      var _isPlaying = false;
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            body: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            AnimatedBuilder(
                animation: _animationController,
                builder: (context, child) {
                  return FloatingActionButton.extended(
                      onPressed: () {
                        setState(() {
                          _isPlaying = !_isPlaying;
                        });
                        if (_animationController.isAnimating)
                          _animationController.stop();
                        else {
                          _animationController.forward(
                              from: _animationController.value == 0.0
                                  ? 1.0
                                  : _animationController.value);
                        }
                      },
                      icon: Icon(
                        _isPlaying ? Icons.pause : Icons.play_arrow,
                        color: Color(0xffF2F2F2),
                      ),
                      label: Text(
                        _animationController.isAnimating ? "Pause" : "Play",
                      ));
                }),
            SizedBox(
              width: 20,
            ),
            AnimatedBuilder(
                animation: _animationController,
                builder: (context, child) {
                  return FloatingActionButton.extended(
                    onPressed: () {
                      setState(() {
                        _isPlaying = !_isPlaying;
                      });
                    },
                    icon: Icon(
                      Icons.refresh,
                      color: Color(0xffF2F2F2),
                    ),
                    label: Text(
                      "Refresh",
                    ),
                  );
                }),
          ],
        ));
      }
    
      @override
      void initState() {
        // TODO: implement initState
        _animationController = AnimationController(
          vsync: this,
          duration: Duration(seconds: 1),
        );
        super.initState();
      }
    }