Flutter-从其他小部件调用setState()

时间:2018-10-11 13:55:12

标签: dart flutter

是否可以从其他窗口小部件setState()方法调用特定窗口小部件(嵌入在其他窗口小部件中)的onPressed(),以便仅重绘该窗口小部件的

我想单击按钮,然后查看“ MyTextWidget”的状态进行更改。其余布局相同,没有任何更改,因此不应重写。

这是我的代码:

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 {

  int _seconds = 1;

  @override
  Widget build(BuildContext context) {
    return 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() {
    //somehow call _updateSeconds()
  }
}

这是我要更新的全状态MyTextWidget。

class MyTextWidget extends StatefulWidget{
  @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,
    );
  }
}

我想要实现的目标似乎很简单,但我无法弄清楚。想象一下,如果“ MyTextWidget”埋在巨大的布局树中,并且每次我想对其进行更新时,我都需要重新绘制整个树。

3 个答案:

答案 0 :(得分:5)

这是使用流的可能解决方案:

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,
    );
  }
}

答案 1 :(得分:1)

有多种方法可以实现这一目标。最简单的方法是使用InheritedWidget小部件,例如:

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;
}

答案 2 :(得分:0)

我是扑扑的初学者。

这是我的修改版本,不确定是否通过这种方式有什么问题,但是可以。

  1. 在类MyTextWidget中添加键值
MyTextWidget({Key key}):super(key:key);
  1. 在类MyHomePage中声明一个GlobalKey
GlobalKey<_MyTextWidgetState> textGlobalKey = new GlobalKey<_MyTextWidgetState>();
  1. 添加MyTextWidget小部件
MyTextWidget(key: textGlobalKey);
  1. 在_addPressed()中调用_updateSeconds()
void _addPressed() {
  //somehow call _updateSeconds()
  textGlobalKey.currentState._updateSeconds(_seconds++);
}

所有代码:

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,
    );
  }
}

希望它会有所帮助:)