Flutter |从最上面的屏幕开始更新导航器堆栈中所有屏幕上的复选框



Hi在我的Flutter应用程序中,我必须在几个屏幕上添加复选框。例如,如果我有6个屏幕作为Screen1、Screen2、Screen3、Screen4、Screen5和Screen6,我可以从Screen1导航到Screen2,从Screen2导航到Scren3,依此类推

我的屏幕堆栈示例

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

这里Screen1是我的根,Screen6是最顶端的屏幕。

如果我在Screen1、Screen2、Screen4和Screen6上有复选框作为

屏幕1(复选框(->屏幕2(复选框(->屏幕3->屏幕4(复选框(->屏幕5->屏幕6(复选框(

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

我用的是flaft_block包装。

请帮忙。

已编辑

如果顶部屏幕(导航器堆栈中(是Screen4或Screen2 ,则需要相同的东西

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

每次在BLOC中调用/添加事件时,都应该采用以前的状态,修改(选中/取消选中一个选项(并发出一个新状态。当一个新的状态被发出时,所有的BlocBuilders都会被重新渲染,这样你的所有屏幕都是最新的(这就是Flutter BLOC的实际工作方式(。

现在,最重要的想法是全局提供创建的BLOC,或者使所有屏幕都可以使用相同的BLOC实例(使用BlocProvider.value-也可以查看有关此主题的附加教程(。通过这种方式,每次您想使用BlocBuilder对复选框进行RENDER时,您将在所有屏幕上获得相同的复选框/状态。

我为您创建了一个完整的示例来说明以上所有内容。只需复制到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的信息,请观看本系列(Flutter BLOC从ZERO到HERO(,尤其是第6集,它解释了一些对你的场景有帮助的概念。

为此,您可以使用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.

相关内容

最新更新