如何在StatefullWidget中将另一个布尔值更改?

时间:2019-03-28 10:15:44

标签: flutter widget state setstate

我是Flutter的新手。

我试图通过按一个按钮来打开面板,而不是通过按该面板上的按钮来关闭它。

我已经设法通过在同一页面中编写代码来做到这一点。

我不能做的就是拆分代码并保持一切正常工作。

我实际上在做的是在初始化为False的小部件的状态中调用变量,然后使用if语句调用:或者是我想要的空容器或面板。

当我按下按钮时,我调用SetState(){},变量变为true以使面板出现,然后面板中有执行相反操作的按钮。

假设我在做什么,这是正确的。如何在新页面中重构面板的情况下继续执行此操作?

我对流和继承的小部件做了一些修改,但我还没有完全理解

3 个答案:

答案 0 :(得分:0)

如果要打开对话框(而不是所谓的“面板”),则可以在再次关闭对话框时简单地返回选定的数据。 您可以在这里找到一个不错的教程:https://medium.com/@nils.backe/flutter-alert-dialogs-9b0bb9b01d28

答案 1 :(得分:0)

如果我的理解正确,您想从另一个StatefullWidget通知StatefullWidget。关于该方法有几种方法,但是由于您已经提到Streams,所以我将尝试发布一个示例并对此情况进行一些解释。

因此,基本上,您可以将流视为一端连接到水龙头的管道,而另一端则将其添加到杯子中(一端可以分成多个端并放入多个杯子中,“广播流”)

现在,杯子是听众(订阅者),它在等待水从管子滴下。

水龙头是发射器,当水龙头打开时,它会发出水滴。

将水龙头的另一端放入杯子时可以打开水龙头,这是一个带有一些凉爽传感器的智能水龙头(发射器将在“检测到用户”时开始发射事件)。

小滴是应用程序中发生的实际事件。

此外,您还必须记住关闭水龙头,以免杯子漏水到厨房地板上。 (完成事件处理后,必须取消订阅者,以免泄漏)。

现在针对您的特殊情况,这是说明上述隐喻的代码段:

class ThePannel extends StatefulWidget { // this is the cup
  final Stream<bool> closeMeStream; // this is the pipe 

  const ThePannel({Key key, this.closeMeStream}) : super(key: key);

  @override
  _ThePannelState createState() => _ThePannelState(closeMeStream);
}

class _ThePannelState extends State<ThePannel> {
  bool _closeMe = false;
  final Stream<bool> closeMeStream;
  StreamSubscription _streamSubscription;

  _ThePannelState(this.closeMeStream);

  @override
  void initState() {
    super.initState();
    _streamSubscription = closeMeStream.listen((shouldClose) { // here we listen for new events coming down the pipe
      setState(() {
        _closeMe = shouldClose; // we got a new "droplet" 
      });
    });
  }

  @override
  void dispose() {
    _streamSubscription.cancel(); // THIS IS QUITE IMPORTANT, we have to close the faucet 
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        SomeWidgetHere(shouldClose: _closeMe), 
        RaisedButton(
          onPressed: () {
            setState(() {
              _closeMe = true;
            });
          },
        )
      ],
    );
  }
}

class SomeWidgetThatUseThePreviousOne extends StatefulWidget { // this one is the faucet, it will emit droplets 
  @override
  _SomeWidgetThatUseThePreviousOneState createState() =>
      _SomeWidgetThatUseThePreviousOneState();
}

class _SomeWidgetThatUseThePreviousOneState
    extends State<SomeWidgetThatUseThePreviousOne> {
  final StreamController<bool> thisStreamWillEmitEvents = StreamController(); // this is the end of the pipe linked to the faucet

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        ThePannel(closeMeStream: thisStreamWillEmitEvents.stream), // we send the other end of the pipe to the cup
        RaisedButton(
          child: Text("THIS SHOULD CLOSE THE PANNEL"),
          onPressed: () {
            thisStreamWillEmitEvents.add(true); // we will emit one droplet here
          },
        ),
        RaisedButton(
          child: Text("THIS SHOULD OPEN THE PANNEL"),
          onPressed: () {
            thisStreamWillEmitEvents.add(false); // we will emit another droplet here
          },
        )
      ],
    );
  }

  @override
  void dispose() {
     thisStreamWillEmitEvents.close(); // close the faucet from this end.
     super.dispose();
  }
}

我希望我的类比可以帮助您了解流概念。

答案 2 :(得分:0)

您可以像这样从另一个屏幕导航并返回数据:

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    title: 'Returning Data',
    home: HomeScreen(),
  ));
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Returning Data Demo'),
      ),
      body: Center(child: SelectionButton()),
    );
  }
}

class SelectionButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      onPressed: () {
        _navigateAndDisplaySelection(context);
      },
      child: Text('Pick an option, any option!'),
    );
  }

  // A method that launches the SelectionScreen and awaits the result from
  // Navigator.pop!
  _navigateAndDisplaySelection(BuildContext context) async {
    // Navigator.push returns a Future that will complete after we call
    // Navigator.pop on the Selection Screen!
    final result = await Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => SelectionScreen()),
    );

    // After the Selection Screen returns a result, hide any previous snackbars
    // and show the new result!
    Scaffold.of(context)
      ..removeCurrentSnackBar()
      ..showSnackBar(SnackBar(content: Text("$result")));
  }
}

class SelectionScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Pick an option'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: RaisedButton(
                onPressed: () {
                  // Close the screen and return "Yep!" as the result
                  Navigator.pop(context, 'Yep!');
                },
                child: Text('Yep!'),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: RaisedButton(
                onPressed: () {
                  // Close the screen and return "Nope!" as the result
                  Navigator.pop(context, 'Nope.');
                },
                child: Text('Nope.'),
              ),
            )
          ],
        ),
      ),
    );
  }
}

有关导航的更多详细信息: https://flutter.dev/docs/cookbook/navigation/returning-data