按下另一个按钮后,列表磁贴按钮会更改状态
Posted
技术标签:
【中文标题】按下另一个按钮后,列表磁贴按钮会更改状态【英文标题】:List tile button changes state after pressing another button 【发布时间】:2022-01-20 21:38:25 【问题描述】:有一个带有列表图块的抽屉,其中包含选中所有和取消选中所有按钮,当我单击选中所有按钮时,它应该选中所有列表项的复选框,但只有在我单击任何其他按钮后 UI 才会更改或更新,取消选中按钮也会产生同样的问题。
drawer: Drawer(
child: Obx(() => ListView(
padding: EdgeInsets.zero,
children: <Widget>[
UserAccountsDrawerHeader(
decoration: BoxDecoration(
color: (Get.isDarkMode) ? Colors.black26 : Colors.grey[300],
),
accountName: Text('Reminders',
style: TextStyle(
fontSize: 30.0,
color: Theme.of(context).textTheme.headline1!.color,
)),
currentAccountPicture: CircleAvatar(
backgroundColor: Colors.white,
child: Image(
image: AssetImage("assets/App_icon.png"),
)),
accountEmail: null,
),
ListTile(
title: Text("Check all",
style: TextStyle(
fontSize: 17.0,
color: Theme.of(context).textTheme.headline1!.color)),
leading: Icon(Icons.check_box),
onTap: ()
checkAll();
,
),
ListTile(
title: Text("Uncheck all",
style: TextStyle(
fontSize: 17.0,
color: Theme.of(context).textTheme.headline1!.color)),
leading: Icon(Icons.check_box_outline_blank),
onTap: ()
unCheckAll();
,
),
ListTile(
title: Text(
(Get.isDarkMode)
? 'Change theme: light'
: 'change theme: dark',
style: TextStyle(
fontSize: 17.0,
color: Theme.of(context).textTheme.headline1!.color),
),
leading: Icon(Icons.color_lens_sharp),
onTap: ()
if (Get.isDarkMode)
Get.changeThemeMode(ThemeMode.light);
else
Get.changeThemeMode(ThemeMode.dark);
,
),
ListTile(
title: Text(
"Delete all",
style: TextStyle(
fontSize: 17.0,
color: Theme.of(context).textTheme.headline1!.color),
),
leading: Icon(Icons.delete),
onTap: ()
todoController.todos.clear();
,
),
ListTile(
title: Text(
"No of tasks: $todoController.todos.length",
style: TextStyle(
fontSize: 20,
color: Theme.of(context).textTheme.headline1!.color),
),
onTap: () ,
),
],
)),
全选和取消全选功能:
void checkAll()
TodoController todoController = Get.put(TodoController());
for (var i = 0; i < todoController.todos.length; i++)
todoController.todos[i].done = true;
GetStorage().write('todos', todoController.todos.toList());
void unCheckAll()
TodoController todoController = Get.put(TodoController());
for (var i = 0; i < todoController.todos.length; i++)
todoController.todos[i].done = false;
GetStorage().write('todos', todoController.todos.toList());
【问题讨论】:
在checkAll
和unCheckAll
中使用setState
。
我试过了,它奏效了,我之前确实尝试过,将它设为有状态小部件并添加设置状态,但在将 Obx 与其他按钮一起使用时它有效,所以不知道是什么导致了问题.
【参考方案1】:
虽然看起来很奇怪,但这样做会解决它:
....
todoController.todos.assignAll(todoController.todos.toList());
GetStorage().write('todos', todoController.todos.toList());
为什么?
假设todoController.todos
是一个RxList,更改列表中各个元素的属性对底层流没有影响。因此,尽管更改了值,但它不会触发 Obx
上的重建。
但是像todoController.todos.assignAll(todoController.todos.toList());
这样的操作实际上会改变 RxList 的底层流/值。因此会触发应有的重建。
当使用 Rx 或 observables 时,请始终牢记Obx/GetX
只会,并且只有在 的实际 value
才会触发重建Rx/Observable 已更改。
todoController.todos[i].done = true;
之类的东西意味着更改 RxList 的第 i 个元素的 done
属性的值,而不是实际 RxList 的值>。 assignAll
就是这样做的。
同样适用于其他Rx。
假设以下是SomeModel
类的Rx
对象:
final someModel= SomeModel().obs;
做类似的事情:
someModel.value.someProperty = someValue;
不会触发 UI 重建,而是执行以下操作:
someModel.value.someProperty = someValue;
someModel.value = someModel.value;
会的。
但这有点奇怪吧?
在这种情况下,copyWith
实用程序方法可能很有用。
【讨论】:
以上是关于按下另一个按钮后,列表磁贴按钮会更改状态的主要内容,如果未能解决你的问题,请参考以下文章
如何更改 UIpickerView 上的元素按下按钮或按下另一个按钮
如何在按下按钮后每 10 分钟重复一次方法并在按下另一个按钮时结束它