颤振从最上方的屏幕更新导航器堆栈中所有屏幕上的复选框

时间:2020-11-02 10:11:20

标签: flutter flutter-bloc

嗨,在我的Flutter应用程序中,我必须在几个屏幕上添加复选框。 例如,如果我有6个屏幕,分别是Screen1,Screen2,Screen3,Screen4,Screen5和Screen6,并且我可以从screen1导航到Screen2,从Screen2导航到Screen3,依此类推。

我的屏幕堆栈示例

屏幕1->屏幕2->屏幕3->屏幕4->屏幕5->屏幕6

这里Screen1是我的根,而Screen6是最上面的屏幕。

如果我在Screen1,Screen2,Screen4和Screen6上有一个复选框,则为

Screen1(复选框)-> Screen2(复选框)-> Screen3-> Screen4(复选框)-> Screen5-> Screen6(复选框)

现在的问题是,如果我选中screen6的复选框,那么必须自动选择(选中)所有其他屏幕上的复选框(不传回结果)

我正在使用flutter_block软件包。

请帮助。

已编辑

(在导航器堆栈中)顶部的Screen是Screen4或Screen2时,需要做同样的事情

2 个答案:

答案 0 :(得分:0)

为此,您可以使用BLOC,这对于初学者来说可能很难,但是为此,另一个技巧是在单独的dart文件上创建另一个类。假设

show the six checked box as Constants.box1 == "selected" ? Showcheckedbox() : showUncheckedBox()  

 // ? means if condition is true : means if condition is false

class Constants {
     string box1 ;
     string box2 ;
     string box3 ;
     string box4 ;
     string box5 ;

}

1. now, when you select the box1 as checked then there you can write it as Constants.box1= "selected";  

 2. and when you pop the screen there you can setState({}) on pop out the screen.

答案 1 :(得分:0)

使用BLOC可以将复选框存储为一种状态,并使用块events触发对该状态的配置更改(选中/取消选中选项)。

每次调用/添加事件时,在BLOC中,都应采用先前的状态,进行修改(选中/取消选中一个选项)并发出新的状态。发出新状态时,所有BlocBuilders都会重新渲染,因此您的所有屏幕都是最新的(这是Flutter BLOC的实际工作方式)。

现在最重要的想法是全局提供所创建的BLOC或使THE SAME BLOC INSTANCE可用于所有屏幕(使用BlocProvider.value-另请参阅此主题的附加教程)。这样,每次您要使用BlocBuilder渲染复选框时,在所有屏幕上都会得到相同的复选框/状态。

我为您创建了完整的示例,以说明上述所有内容。只需复制到main.dart并运行。花些时间阅读错误的注释和歉意(如果有的话,要写一点时间)。

import 'package:bloc/bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

///
/// I put the checkboxes globally because I do not know how you have access to
/// them but you are free to put whenever you want as soon as they are passed
/// to the BLOC. You can even add them inside the BLOC.
///
final List<Checky> gCheckboxes = [
  Checky("Checkbox 1"),
  Checky("Checkbox 2"),
  Checky("Checkbox 3"),
  Checky("Checkbox 4"),
  Checky("Checkbox 5"),
  Checky("Checkbox 6"),
  Checky("Checkbox 7"),
];

void main() {
  runApp(CheckyApp());
}

///
/// This widget is the root of your application.
///
class CheckyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // For demo sake I will expose the BLOC globally
    return BlocProvider<CheckyCubit>(
        create: (context) => CheckyCubit(gCheckboxes),
        child: MaterialApp(
          title: 'Checky App',
          theme: ThemeData(
            primarySwatch: Colors.blue,
            visualDensity: VisualDensity.adaptivePlatformDensity,
          ),
          initialRoute: "/screen_1",
          routes: {
            '/screen_1': (context) => GenericScreen(1),
            '/screen_2': (context) => GenericScreen(2),
            '/screen_3': (context) => GenericScreen(3),
            '/screen_4': (context) => GenericScreen(4),
            '/screen_5': (context) => GenericScreen(5),
            '/screen_6': (context) => SummaryScreen(),
          },
        ));
  }
}

///
/// A generic screen to demonstrate that data can be accessed among multiple
/// screens
///
class GenericScreen extends StatelessWidget {
  ///
  /// This is used to create the generic screen and navigation buttons
  ///
  final int id;

  const GenericScreen(this.id, {Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Stack(children: [
      Scaffold(
        appBar: AppBar(
          title: Text("Checky :: Screen ${this.id}"),
        ),
        body: BlocBuilder<CheckyCubit, CheckyState>(
          builder: (context, state) {
            return ListView.builder(
              itemCount: state.checkboxes.length ?? 0,
              itemBuilder: (context, index) =>
                  // Render the checkbox based on state data from BLOC.
                  // Here I just emulated the checkbox for the sake of example
                  GestureDetector(
                onTap: () =>
                    BlocProvider.of<CheckyCubit>(context).toggle(index),
                child: Container(
                  padding: EdgeInsets.all(10),
                  margin: EdgeInsets.all(5),
                  color: state.checkboxes[index].isChecked
                      ? Colors.amberAccent
                      : Colors.white,
                  child: Text(state.checkboxes[index].label),
                ),
              ),
            );
          },
        ),
      ),
      // THIS IS NOT IMPORTART FOR YOUR PURPOSE
      if (Navigator.of(context).canPop())
        Align(
          alignment: Alignment.bottomLeft,
          child: Container(
            margin: EdgeInsets.all(20),
            child: FloatingActionButton(
              heroTag: "previous_$id",
              child: Icon(Icons.chevron_left),
              onPressed: () => Navigator.of(context).pop(),
            ),
          ),
        ),
      if (this.id <= 5)
        Align(
          alignment: Alignment.bottomRight,
          child: Container(
            margin: EdgeInsets.all(20),
            child: FloatingActionButton(
              heroTag: "next_$id",
              child: Icon(Icons.chevron_right),
              onPressed: () =>
                  Navigator.of(context).pushNamed("/screen_${id + 1}"),
            ),
          ),
        ),
    ]);
  }
}

///
/// Last screen where we just display the values by accessing the CheckyBloc.
///
class SummaryScreen extends StatelessWidget {
  const SummaryScreen({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Stack(children: [
      Scaffold(
        appBar: AppBar(
          title: Text("Checky :: Summary"),
        ),
        body: BlocBuilder<CheckyCubit, CheckyState>(
          builder: (context, state) {
            return ListView.builder(
              itemCount: state.checkboxes.length ?? 0,
              itemBuilder: (context, index) =>
                  // Render only checked options
                  state.checkboxes[index].isChecked
                      ? Container(
                          padding: EdgeInsets.all(10),
                          margin: EdgeInsets.all(5),
                          color: state.checkboxes[index].isChecked
                              ? Colors.greenAccent
                              : Colors.white,
                          child: Text(state.checkboxes[index].label),
                        )
                      : SizedBox.shrink(),
            );
          },
        ),
      ),
      Align(
        alignment: Alignment.bottomLeft,
        child: Container(
          margin: EdgeInsets.all(20),
          child: FloatingActionButton(
            heroTag: "Reset",
            child: Icon(Icons.refresh),
            onPressed: () {
              // Reset the options
              BlocProvider.of<CheckyCubit>(context).reset();
              // Push to the first screen
              Navigator.of(context).pushNamed("/screen_1");
            },
          ),
        ),
      ),
    ]);
  }
}

// =============================================================================

///
/// Checkbox entity which stores the label and whether is selected or not.
///
class Checky {
  ///
  /// Checkbox displayed label
  ///
  final String label;

  ///
  /// Tells whether the checkbox is selected
  ///
  bool isChecked;

  ///
  /// Checkbox constructor. Default the checkbox is unchecked.
  ///
  Checky(this.label, {this.isChecked = false});

  ///
  /// Check the checkbox ;)
  ///
  void check() {
    this.isChecked = true;
  }

  ///
  /// Uncheck the checkbox ;)
  ///
  void uncheck() {
    this.isChecked = false;
  }

  ///
  /// Uncheck the checkbox ;)
  ///
  void toggle() {
    this.isChecked = !this.isChecked;
  }
}

///
/// Checkboxes state that is sent from BLOC and only contains a list of
/// checkboxes (current checkboxes configuration).
///
class CheckyState {
  ///
  /// The checkboxes list
  ///
  final List<Checky> checkboxes;

  CheckyState(this.checkboxes);
}

///
/// Checkboxes logic. Takes the current state and modifies the checkboxes and
/// then emit the new configuration on the "output" stream.
///
class CheckyCubit extends Cubit<CheckyState> {
  ///
  /// Cubit constructor which emits the first/default checkboxes and their
  /// configuration (ehich one are checked or not).
  ///
  CheckyCubit(List<Checky> checkboxes) : super(CheckyState(checkboxes));

  // ==================================
  // EVENTS
  // ==================================

  ///
  /// Toggle a checkbox by index
  ///
  void toggle(int index) async {
    // Retrieve the current checkboxes from the last emited state
    var checkboxes = this.state.checkboxes;

    // Just take some precautions but this depends by your implementation
    if (checkboxes != null && checkboxes[index] != null) {
      // Toggle the checkbox by given index
      checkboxes[index].toggle();
    }
    // Emit the new state/configuration
    emit(CheckyState(checkboxes));
  }

  ///
  /// Reset the entire by unchecking all options.
  ///
  void reset() {
    // Retrieve the current checkboxes
    var checkboxes = this.state.checkboxes;

    // Uncheck all of them
    checkboxes.forEach((checkbox) {
      checkbox.uncheck();
    });

    // Emit the new state/configuration
    emit(CheckyState(checkboxes));
  }
}

如果您想进一步了解Flutter BLOC,请观看this series (Flutter BLOC from ZERO to HERO)-特别是第6集,其中介绍了一些可以帮助您解决问题的概念。