Flutter 从相关的小部件类更改状态
Posted
技术标签:
【中文标题】Flutter 从相关的小部件类更改状态【英文标题】:Flutter change state from related widget class 【发布时间】:2021-05-28 13:48:11 【问题描述】:让我们假设一个类“SpecialButton”及其状态类“SpecialButtonState”
class SpecialButton extends StatefulWidget
bool active = false;
SpecialButton(Key key) : super(key: key);
@override
SpecialButtonState createState() => SpecialButtonState();
class SpecialButtonState extends State<SpecialButton>
@override
void initState()
super.initState();
@override
Widget build(BuildContext context)
return Container(
decoration:
BoxDecoration(color: this.widget.active ? COLOR_1 : COLOR_2),
child: null);
在父窗口小部件中,我管理其中的几个按钮。因此,我想为他们分配一个状态。我尝试的解决方案是在 SpecialButton 类中引入一个“活动”标志,我可以轻松地从父小部件将其设置为 true 或 false。然后我可以在状态类的构建函数中使用它来为按钮着色。不幸的是,这并不完全有效,因为它不会立即更新按钮(它需要某种状态更新,例如通过将鼠标悬停在元素上)。
我的第二个想法是将此标志作为 SpecialButtonState 类的固有状态引入
class SpecialButton extends StatefulWidget
SpecialButton(Key key) : super(key: key);
@override
SpecialButtonState createState() => SpecialButtonState();
class SpecialButtonState extends State<SpecialButton>
bool active;
@override
void initState()
super.initState();
this.active = false;
activate()
this.setState(()
active = true;
);
deactivate()
this.setState(()
active = false;
);
@override
Widget build(BuildContext context)
return Container(
decoration: BoxDecoration(color: this.active ? COLOR_1 : COLOR_2),
child: null);
据我了解,这将是使用颤振的正确方法,但似乎我无法从 SpecialButton 类或包含小部件的父类访问“激活”或“停用”功能。
所以我的问题是:我如何(直接或间接通过函数)从相应的 StatefulWidget 类或包含它的父 Widget 修改状态?
在 Stack Overflow 上已经有一些类似的问题,我可以在其中找到使用或不使用全局键的提示,我发现这种行为具有误导性。此外,由于颤振的快速发展,它们可能已经过时,所以我再次就这个确切的用例提出这个(类似的)问题。
编辑:我忘了提到在创建后更改此标志至关重要,因此它将在其生存期间多次更改。这需要重新绘制小部件。
【问题讨论】:
你的第一个想法是正确的,它甚至可以是一个无状态的小部件。也许你可以用它来描述你的问题。您的第二个解决方案不是 Flutter 是如何做到的。 【参考方案1】:您不必为SpecialButton
使用有状态小部件。您可以使用无状态小部件和键处理 active
标志。示例代码:
class SomeParent extends StatefulWidget
const SomeParent(Key key) : super(key: key);
@override
State<SomeParent> createState() => SomeParentState();
class SomeParentState extends State<SomeParent>
bool _button1IsActive = false;
bool _button2IsActive = false;
@override
Widget build(BuildContext context)
return Scaffold(
body: Column(
children: [
SpecialButton(
key: UniqueKey(),
active: _button1IsActive,
),
SizedBox(height: 8),
SpecialButton(
key: UniqueKey(),
active: _button2IsActive,
),
SizedBox(height: 16),
TextButton(
child: Text('Toggle button 1'),
onPressed: ()
setState(()
_button1IsActive = !_button1IsActive;
);
,
),
SizedBox(height: 8),
TextButton(
child: Text('Toggle button 2'),
onPressed: ()
setState(()
_button2IsActive = !_button2IsActive;
);
,
),
],
),
);
class SpecialButton extends StatelessWidget
final bool active;
const SpecialButton(Key key, this.active = false) : super(key: key);
@override
Widget build(BuildContext context)
return Container(
height: 40,
width: 40,
decoration: BoxDecoration(color: active ? Colors.red : Colors.blue),
);
SomeParent
是我的幻想,例如。不知道你的父母是什么。
键在这里很重要。它们告诉小部件树何时应该重建具有相同类型的特定小部件(例如SpecialButton
)。
请尝试这种方法,它应该可以工作。
【讨论】:
我明白了,所以我确实错过了那些键。不幸的是,我不知道父级将包含多少个特殊按钮,因此我创建了一个列表。 ValueKey 函数似乎不适用于数组:Duplicate Keys found: If multiple keyed nodes exist as children of another node, they must have unique keys
。因此,我在父级中创建了一个布尔值列表,并尝试通过key: ValueKey(this.btnActive[i])
为每个 SpecialButton 设置参数...有解决方法吗?
哦,我的错,你不应该在这里使用布尔值键。解决方法非常简单 - 使用 UniqueKey()
。我更新了我的答案。【参考方案2】:
正如 nvoigt 所说,您的按钮甚至可以是无状态小部件,但它们的父级应该是有状态的,您应该为它们提供相应的值。例如:
import 'package:flutter/material.dart';
class Parent extends StatefulWidget
@override
_ParentState createState() => _ParentState();
class _ParentState extends State<Parent>
bool isEnabled = false;
@override
Widget build(BuildContext context)
return Column(
children: [
StateLessButton1(isEnabled: isEnabled),
StateLessButton1(isEnabled: !isEnabled),
FloatingActionButton(onPressed: ()
setState(()
isEnabled = !isEnabled;
);
)
],
);
现在它只取决于您何时想要更改该值。如果你想在你的按钮中改变它,我建议你使用一个带有 ChangeNotifier 的类和一个里面的函数来改变值。否则我建议不要将你的树分成多个文件
【讨论】:
以上是关于Flutter 从相关的小部件类更改状态的主要内容,如果未能解决你的问题,请参考以下文章