Как мне изменить логическое значение в StatefullWidget от другого? - PullRequest
0 голосов
/ 28 марта 2019

Я новичок во Флаттере.

Я пытаюсь открыть панель, нажав кнопку, а затем закрывая ее, нажав кнопку на этой панели.

Мне удалось сделать это, написав код на той же странице.

Что я не могу сделать, так это разделить код и заставить все работать.

Что я на самом деле делаю, так это вызываю переменную в состоянии виджета, которая инициализируется False, а затем с помощью оператора if, который я вызываю: или пустого контейнера, или панели, которую я хочу.

Когда я нажимаю кнопку, я вызываю SetState () {}, и переменная меняется на true, чтобы появилась панель, а затем на панели появляется кнопка, которая делает противоположное действие.

Предполагая, что то, что я делаю, правильно. Как мне продолжать делать это с панелью, измененной на новой странице?

У меня есть что-то о потоках и унаследованных виджетах, но я не до конца понял

Ответы [ 3 ]

0 голосов
/ 28 марта 2019

Если я правильно понимаю, вы хотите уведомить 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();
  }
}

Я надеюсь, что моя аналогияпоможет вам немного понять концепцию потоков.

0 голосов
/ 28 марта 2019

вы можете перемещаться и возвращать данные с другого экрана, например:

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

0 голосов
/ 28 марта 2019

Если вы хотите открыть диалоговое окно (вместо того, что вы называете «панелью»), вы можете просто вернуть выбранные данные, когда снова закроете диалоговое окно. Вы можете найти хороший учебник здесь: https://medium.com/@nils.backe/flutter-alert-dialogs-9b0bb9b01d28

...