我是 Flutter 的新手,在尝试进行自定义切换时遇到了第一个障碍。我的开关在功能上应该与实际的 Switch
相同。从 Material 库来看,唯一的区别就是UI。
我正在使用 ValueNotifier
和 ValueListenableBuilder
从另一个小部件更新开关值。这是我的代码的相关部分:
包含小部件
class ParentWidget extends StatefulWidget {
@override
_ParentWidget createState() => _ParentWidget();
}
class _ParentWidgetState extends State<ParentWidget> {
ValueNotifier _switchNotifier = ValueNotifier(false);
@override
Widget build(BuildContext context) {
return Container(
child: ValueListenableBuilder(
valueListenable: _switchNotifier,
builder: (context, switchValue, child) {
return _buildSwitch(switchValue);
},
),
);
}
Widget _buildSwitch(bool switchValue) {
return CustomSwitch(
key: Key(value.toString()),
initValue: switchValue,
onChanged: (value) {
setState(() {
_switchNotifier.value = value;
});
},
);
}
}
改变开关值的小部件
class ChildWidget extends StatefulWidget {
final ValueNotifier _switchNotifier;
ChildWidget(this._switchNotifier);
@override
_ChildWidgetState createState() => _ChildWidgetState();
}
class _ChildWidgetState extends State<ChildWidget> {
@override
Widget build(BuildContext context) {
return Container(
child: GestureDetector(
onTap: () {
widget._switchNotifier.value = false;
},
child: Image(...),
),
);
}
}
自定义开关
class CustomSwitch extends StatefulWidget {
final ValueChanged<bool> onChanged;
final bool initValue;
final Key key;
const CustomSwitch({
@required this.key,
this.onChanged,
this.initValue,
});
@override
_CustomSwitchState createState() => _CustomSwitchState();
}
class _CustomSwitchState extends State<CustomSwitch> {
bool value;
@override
void initState() {
value = widget.initValue;
super.initState();
}
@override
Widget build(BuildContext context) {
// the switch/toggle is animated just like the Material Switch
return TheSwitch(...);
}
_toggle() {
setState(() {
value = !value;
widget.onChanged(value);
});
}
}
如果我调用
_toggle()
来自 CustomSwitch
开关会随着动画很好地切换(我使用 AnimatedPositioned
作为开关)。如果我只依赖用户输入,这很好用,但我还需要以编程方式切换开关,我觉得我错过了一些基本的东西,但我很难过。我目前的理解是
CustomSwitch
每次我将其值从 ChildWidget
更改时都会重建因为我将开关值用作 Key
,但是如何用动画很好地做到这一点,就好像我在调用 _toggle()
建成后?就像在 Java 中一样,您通常会执行
customSwitch.toggle()
之类的操作。 .
最佳答案
大多数 flutter 小部件使用 Controller 与外部小部件交互(TextFormField、ListView 等)。
对于您的问题,最简单的解决方案也是创建一个自定义 Controller 。
首先,您将创建一个 Controller 类,它将您的自定义小部件的状态作为参数。此类还将公开您的小部件的方法。它看起来像这样:
class CustomWidgetController{
_CustomWidgetState _customWidgetState;
void _addState(_CustomWidgetState customWidgetState){
this._customWidgetState = customWidgetState;
}
/// Determine if the CustomWidgetController is attached to an instance
/// of the CustomWidget (this property must return true before any other
/// functions can be used)
bool get isAttached => _customWidgetState != null;
/// Here is the method you are exposing
void toggle() {
assert(isAttached, "CustomWidgetController must be attached to a CustomWidget");
_customWidgetState.toggle();
}
}
您需要接受 Custom Controller 作为 CustomWidget 中的参数,并将其传递给它的状态,如下所示:class CustomSwitch extends StatefulWidget {
final CustomWidgetController customWidgetController;
final bool initValue;
final Key key;
const CustomSwitch({
@required this.key,
this.customWidgetController,
this.initValue,
});
@override
_CustomSwitchState createState() => _CustomSwitchState(customWidgetController, initValue);
}
在您的自定义类的状态中,您将使用我们创建的 addState 方法将您的类的状态分配给 Controller 。您可以像这样构造函数:class _CustomSwitchState extends State<CustomSwitch> {
final CustomWidgetController _customWidgetController;
bool value;
_CustomSwitchState(this._customWidgetController, this.value) {
if (_customWidgetController != null)
_customWidgetController._addState(this);
}
@override
Widget build(BuildContext context) {
// the switch/toggle is animated just like the Material Switch
return TheSwitch(...);
}
toggle() {
setState(() {
value = !value;
});
}
}
现在,您可以使用父小部件中的 Controller 传递 Controller 并调用方法,如下所示: CustomWidgetController customWidgetController = new CustomWidgetController();
@override
Widget build(BuildContext context) {
return CustomWidget(
controller: customWidgetController,
initValue: true
);
}
就是这个!现在您可以调用customWidgetController.toggle()
在代码中的任何位置切换值!这就是原生小部件让您与它们交互的方式。
关于Flutter如何以编程方式调用自定义小部件中的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59809686/