Search code examples
flutterdartrxdartflutter-getx

Flutter and Getx: How an observable emit changes


I have a little bar that changes color when the user move the container and when the user stop touching the container. I´m using a Listener widget and the functions onPointerMove which calls a GetxController with value of true and onPointerUp with value of false so the color of the container changes according to a RxBool in the controller.
My question is: while calling onPointerMove the RxBool changes to a true value but I don´t know if the value is always emitted even though it´s the same, because then my widget will redraw every time; or if the value doesn´t emmit anything because it´s the same.

Here is the controller

  RxBool isPressing = false.obs;

  void changeColor(bool i) => i ? isPressing.value = true : isPressing.value = false;

Here is the listener widget

 Listener(
      onPointerMove: (PointerEvent e) => _touchController.changeColor(true),
      onPointerUp: (PointerUpEvent e) => _touchController.changeColor(false),
      .
      .
      .
          children: [
            Obx(() => Container(
              height: 100,
              width: 4,
              decoration: BoxDecoration(
                color: _touchController.isPressing.value ? primaryColor : Colors.white,
                borderRadius: BorderRadius.circular(10),
              ),
            )),

Solution

  • If you turn the Container in a StatelessWidget and print something in the build method, you may notice that it's not emitted when the value is the same.

    import 'package:flutter/material.dart';
    import 'package:get/get.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key? key, required this.title}) : super(key: key);
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      MainController _touchController = Get.put(MainController());
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Listener(
            onPointerMove: (PointerEvent e) =>
                _touchController.changeColor(true),
            onPointerUp: (PointerUpEvent e) =>
                _touchController.changeColor(false),
            child: Obx(() => Box(
              isPressing: _touchController.isPressing.value,
            )),
          ),
        );
      }
    }
    
    class Box extends StatelessWidget {
      final bool isPressing;
    
      const Box({Key? key, required this.isPressing}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        print('re build');
        return Container(
          height: 100,
          width: 100,
          decoration: BoxDecoration(
            color: isPressing ? Colors.white : Colors.red,
            borderRadius: BorderRadius.circular(10),
          ),
        );
      }
    }
    
    class MainController extends GetxController {
      RxBool isPressing = false.obs;
    
      void changeColor(bool i) =>
          i ? isPressing.value = true : isPressing.value = false;
    }