Flutter - calling setState() from other widget

后端 未结 3 1200
臣服心动
臣服心动 2020-12-17 10:25

Is it possible to call setState() of particular widget (embedded in other widgets) from other widgets onPressed() method so only that

相关标签:
3条回答
  • 2020-12-17 10:40

    This is a possible solution using streams:

    import 'dart:async';
    
    import 'package:flutter/material.dart';
    void main() => runApp(new MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'Timer',
          theme: new ThemeData(
            primaryColor: Colors.grey.shade800,
          ),
          home: new MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatelessWidget {
    
      StreamController<int> _controller = StreamController<int>();
    
      int _seconds = 1;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("title"),
          ),
          body: Column(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              MyTextWidget(stream: _controller.stream), //just update this widget
              Divider(),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: <Widget>[
                  IconButton(
                    icon: Icon(Icons.add_circle),
                    onPressed: _addPressed,
                    iconSize: 150.0,
                  ),
                  IconButton(
                    icon: Icon(Icons.remove_circle),
                    onPressed: ()=> _controller.add(_seconds++),
                    iconSize: 150.0,
                  ),
                ],
              )
            ],
          ),
        );
      }
    
      void _addPressed() {
        //somehow call _updateSeconds()
      }
    }
    
    class MyTextWidget extends StatefulWidget{
    
      final Stream<int> stream;
    
      MyTextWidget({this.stream});
    
      @override
      _MyTextWidgetState createState() => _MyTextWidgetState();
    }
    
    class _MyTextWidgetState extends State<MyTextWidget> {
    
      int secondsToDisplay = 0;
    
      void _updateSeconds(int newSeconds) {
        setState(() {
          secondsToDisplay = newSeconds;
        });
      }
    
      @override
      void initState() {
        super.initState();
        widget.stream.listen((seconds) {
          _updateSeconds(seconds);
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Text(
          secondsToDisplay.toString(),
          textScaleFactor: 5.0,
        );
      }
    }
    
    0 讨论(0)
  • 2020-12-17 10:46

    There are different ways on how to achieve this. The really simple one is with InheritedWidget widget, like that:

    import 'package:flutter/material.dart';
    
    void main() => runApp(new MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'Timer',
          theme: new ThemeData(
            primaryColor: Colors.grey.shade800,
          ),
          home: new MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      @override
      MyHomePageState createState() {
        return new MyHomePageState();
      }
    }
    
    class MyHomePageState extends State<MyHomePage> {
      int _seconds = 1;
    
      @override
      Widget build(BuildContext context) {
        return new MyInheritedWidget(
          secondsToDisplay: _seconds,
          child: Scaffold(
    
            appBar: AppBar(
              title: Text("title"),
            ),
            body: Column(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: <Widget>[
                MyTextWidget(), //just update this widget
                Divider(),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: <Widget>[
                    IconButton(
                      icon: Icon(Icons.add_circle),
                      onPressed: _addPressed,
                      iconSize: 150.0,
                    ),
                    IconButton(
                      icon: Icon(Icons.remove_circle),
                      onPressed: () => print("to be implemented"),
                      iconSize: 150.0,
                    ),
                  ],
                )
              ],
            ),
          ),
        );
      }
    
      void _addPressed() {
        setState(() {
          _seconds++;
        });
      }
    }
    
    class MyTextWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        final MyInheritedWidget inheritedWidget = MyInheritedWidget.of(context);
        return Text(inheritedWidget.secondsToDisplay.toString(),
          textScaleFactor: 5.0,
        );
      }
    }
    
    class MyInheritedWidget extends InheritedWidget {
      final int secondsToDisplay;
    
      MyInheritedWidget({
        Key key,
        @required this.secondsToDisplay,
        @required Widget child,
      }) : super(key: key, child: child);
    
      static MyInheritedWidget of(BuildContext context) {
        return context.inheritFromWidgetOfExactType(MyInheritedWidget);
      }
    
      @override
      bool updateShouldNotify(MyInheritedWidget oldWidget) =>
          secondsToDisplay != oldWidget.secondsToDisplay;
    }
    
    0 讨论(0)
  • 2020-12-17 10:50

    I'm a beginner of flutter.

    This is my modified version, not sure if there is anything wrong via this way, but it works.

    1. Add key value in class MyTextWidget
    MyTextWidget({Key key}):super(key:key);
    
    1. Declare a GlobalKey in class MyHomePage
    GlobalKey<_MyTextWidgetState> textGlobalKey = new GlobalKey<_MyTextWidgetState>();
    
    1. Add MyTextWidget widget
    MyTextWidget(key: textGlobalKey);
    
    1. Call _updateSeconds() in _addPressed()
    void _addPressed() {
      //somehow call _updateSeconds()
      textGlobalKey.currentState._updateSeconds(_seconds++);
    }
    

    All code:

    import 'package:flutter/material.dart';
    void main() => runApp(new MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'Timer',
          theme: new ThemeData(
            primaryColor: Colors.grey.shade800,
          ),
          home: new MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatelessWidget {
    
      GlobalKey<_MyTextWidgetState> textGlobalKey = new GlobalKey<_MyTextWidgetState>();
    
      int _seconds = 1;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("title"),
          ),
          body: Column(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              MyTextWidget(key: textGlobalKey), //just update this widget
              Divider(),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: <Widget>[
                  IconButton(
                    icon: Icon(Icons.add_circle),
                    onPressed: _addPressed,
                    iconSize: 150.0,
                  ),
                  IconButton(
                    icon: Icon(Icons.remove_circle),
                    onPressed: ()=> print("to be implemented"),
                    iconSize: 150.0,
                  ),
                ],
              )
            ],
          ),
        );
      }
    
      void _addPressed() {
        //somehow call _updateSeconds()
        textGlobalKey.currentState._updateSeconds(_seconds++);
      }
    }
    
    class MyTextWidget extends StatefulWidget{
    
      MyTextWidget({Key key}):super(key:key);
    
      @override
      _MyTextWidgetState createState() => _MyTextWidgetState();
    }
    
    class _MyTextWidgetState extends State<MyTextWidget> {
    
      int secondsToDisplay = 0;
    
      void _updateSeconds(int newSeconds) {
        setState(() {
          secondsToDisplay = newSeconds;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Text(
          secondsToDisplay.toString(),
          textScaleFactor: 5.0,
        );
      }
    }
    

    Hope it helps :)

    0 讨论(0)
提交回复
热议问题