skip to Main Content

Suppose i have widget tree like this.

Widget1(
      void someEvent(){
        if(true){
          
        }
      }

      child: Widget2(
        child: Widget3(
          child: Widget4(
            void someFunction(){
            //called when event occurs in Widget1
            }
            child:Container()
          ),
        ),
      ),
    )

Suppose if some events occurs in Widget1 and if some condition is true then in Widget4 i should call a function automatically.

The someEvent function can be called many times and if condition is true then
the Widget4 should call its custom function that many times.

How can i achieve the requirements which i mentioned?

2

Answers


  1. You can use InheritedWidget

    class MyInheritedData extends InheritedWidget {
      const MyInheritedData({
        super.key,
        required super.child,
        required this.valueChangedBySomeEvent,
        this.someFunction,
      });
    
      final dynamic valueChangedBySomeEvent;
      final Function()? someFunction;
    
      static MyInheritedData of(BuildContext context) {
        final MyInheritedData? result = context.dependOnInheritedWidgetOfExactType<MyInheritedData>();
        assert(result != null, 'No MyInheritedWidget found in context');
        return result!;
      }
    
      @override
      bool updateShouldNotify(MyInheritedData oldWidget) {
        // your condition can be customized here
        return valueChangedBySomeEvent != oldWidget.valueChangedBySomeEvent &&
        someFunction != oldWidget.someFunction;
      }
    }
    
    class Widget1 extends StatefulWidget {
      const Widget1({super.key, required this.child});
      
      final Widget child;
    
      @override
      State<Widget1> createState() => _Widget1State();
    }
    
    class _Widget1State extends State<Widget1> {
      bool valueChangedBySomeEvent = false;
      
      someEvent() {
        setState(() {
          valueChangedBySomeEvent = !valueChangedBySomeEvent;
        });
      }
      
      @override
      Widget build(BuildContext context) {
        return GestureDetector(
          onTap: someEvent,
          child: MyInheritedData(
            valueChangedBySomeEvent: valueChangedBySomeEvent,
            child: widget.child,
          ),
        );
      }
    }
    
    class Widget4 extends StatefulWidget {
      const Widget4({super.key});
    
      @override
      State<Widget4> createState() => _Widget4State();
    }
    
    class _Widget4State extends State<Widget4> {
      
      @override
      void didChangeDependencies() {
        final myInheritedData = MyInheritedData.of(context);
        // callFunction (you can add some conditions here also)
        myInheritedData.someFunction?.call();
        super.didChangeDependencies();
      }
    
      @override
      Widget build(BuildContext context) {
        return Container();
      }
    }
    

    whenever the parent widget of MyInheritedData is built, (Widget1) MyInheritedData.updateShouldNotify is triggered and if it returns true,
    then all descendants (Widget4) will trigger their didChangeDependencies.

    Edit

    InheritedWidget is built in flutter. you can use a state management package if you want to write less code. here is an example using riverpod:

    void main() {
      // wrap your entire application with ProviderScope to
      // enable riverpod
      runApp(const ProviderScope(child: MyApp()));
    }
    
    // you can access this provider anywhere in your app
    final triggerProvider = StateProvider<bool>((ref) => true);
    
    class Widget1 extends ConsumerWidget {
      const Widget1({super.key});
    
      someEvent(WidgetRef ref) {
        if (true) {
          // toggle triggerProvider whenever the condition is true
          ref.read(triggerProvider.notifier).update((state) => !state);
        }
      }
    
      @override
      Widget build(BuildContext context, WidgetRef ref) {
    
        return GestureDetector(
          onTap: () => someEvent(ref),
        );
      }
    }
    
    class Widget4 extends ConsumerWidget {
      const Widget4({super.key});
    
      someFunction() {}
    
      @override
      Widget build(BuildContext context, WidgetRef ref) {
    
        ref.listen(triggerProvider, (previous, next) {
          // call your function whenever the provider is toggled
          someFunction();
        });
    
        return Container();
      }
    }
    
    Login or Signup to reply.
  2. You can achieve this by using a callback function.

      class Widget1 extends StatefulWidget {
      final VoidCallback onSomeEvent;
    
      Widget1({required this.onSomeEvent});
    
      @override
      _Widget1State createState() => _Widget1State();
    }
    
    class _Widget1State extends State<Widget1> {
      void someEvent() {
        if (true) {
          widget.onSomeEvent();
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return Widget2(
          child: Widget3(
            child: Widget4(
              onSomeFunction: widget.onSomeEvent,
              child: Container(),
            ),
          ),
        );
      }
    }
    
    class Widget4 extends StatelessWidget {
      final VoidCallback onSomeFunction;
    
      Widget4({required this.onSomeFunction});
    
      @override
      Widget build(BuildContext context) {
        return ElevatedButton(
          onPressed: onSomeFunction,
          child: Text('Button'),
        );
      }
    }
    

    Widget1 has a callback function onSomeEvent that is passed to Widget4 through the widget tree. When someEvent is called in Widget1, it calls the onSomeEvent callback function, which is then executed in Widget4.

    You can also use a state management solution like Provider.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search