提取的小部件内的 Flutter Slider
Flutter Slider inside a Extracted Widget
好的,我想说得更具体一些。我的目标是将我的部分代码 细分为单独的小部件 以便主树尽可能保持干净。
在下面的示例中,我在 StatefulWidget 中有一个 主树。我已经成功地将带有按钮 的容器转换成它自己的带有Extract to Widget 的小部件。按钮的 setState 通过 constructor.
起作用
现在我想对第二个装有滑块的容器做同样的事情。但是我不知道如何使用构造函数 处理 Slider onChanged setState,因为 setState 在提取的 Widget 中不起作用。
这是代码示例,工作按钮作为提取的小部件,滑块仍在主树中。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyStfl(),
);
}
}
class MyStfl extends StatefulWidget {
@override
_MyStflState createState() => _MyStflState();
}
class _MyStflState extends State<MyStfl> {
double sliderPos = 0.0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: BoxDecoration(
color: Color(0x80061A28),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: MyCardA(
aktion: () {
setState(() {
print('Button Pressed');
});
},
),
),
Expanded(
child: Container(
child: Slider(
divisions: 48,
value: sliderPos,
min: 0.0,
max: 24.0,
onChanged: (double newValue) {
setState(
() {
sliderPos = double.parse(newValue.toStringAsFixed(1));
print(sliderPos);
},
);
},
),
),
),
],
),
),
);
}
}
class MyCardA extends StatelessWidget {
MyCardA({this.aktion});
final Function aktion;
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(20.0),
padding: EdgeInsets.all(20.0),
color: Color(0x80125889),
child: GestureDetector(
onTap: aktion,
child: Text(
'MY BUTTON',
style: TextStyle(
color: Color(0xFF3D3939),
fontSize: 22.0,
),
),
),
);
}
}
首先,您要在 CardA
组件中更改一件事。不要将 aktion
参数键入 Function
(这非常通用),您应该给它一个类型 void Function()
,说:它是一个 return 什么都没有的函数(空白)。这就是 GestureDetector
的 onTap
参数所期望的。传递任何其他类型的函数不是您想要做的事情,因为它会破坏您的应用程序。键入参数时尽可能具体。您可以将此 void Function()
类型缩短为 VoidCallback
。都是一样的。
我也做了参数required
。这不是必需的,但它是你想要的(我认为)。如果您希望能够发出此参数,请删除 required
关键字并将您的 aktion
键入 void Function()?
。 ?
表示您可以传递 void Function()
或 null
.
class MyCardA extends StatelessWidget {
MyCardA({required this.aktion});
final void Function() aktion;
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(20.0),
padding: EdgeInsets.all(20.0),
color: Color(0x80125889),
child: GestureDetector(
onTap: aktion,
child: Text(
'MY BUTTON',
style: TextStyle(
color: Color(0xFF3D3939),
fontSize: 22.0,
),
),
),
);
}
}
对于'MyCardB',您需要设置一个带有参数的回调函数。有点复杂。
一个Slider
组件有一个onChanged
参数,当滑块位置改变时触发。这为您提供了一个 double
(新位置)并允许您使用它做一些事情。这被键入为 void Function(double)
。我们有一个函数获取一个 double
作为参数,return 什么都没有 (void
).
您可以在下面的自定义组件中看到它的外观。
class MyCardB extends StatelessWidget {
const MyCardB({
required this.sliderPos,
required this.onChanged,
});
final double sliderPos;
final void Function(double) onChanged;
@override
Widget build(BuildContext context) {
return Container(
child: Slider(
divisions: 48,
value: sliderPos,
min: 0.0,
max: 24.0,
onChanged: onChanged,
),
);
}
}
然后您在主组件中使用这个新组件,如下所示。
Expanded(
child: MyCardB(
sliderPos: sliderPos,
onChanged: (double newValue) {
setState(
() {
sliderPos = double.parse(newValue.toStringAsFixed(1));
},
);
},
),
),
长话短说,您想利用 callback functions
。如果您不熟悉它们,我强烈建议您仔细阅读它们,它们非常重要。正如您正确注意到的那样,您无法执行 child 小部件内的逻辑;您想将其保留在 parent 中。您可以通过创建这些回调函数来管理它。
您在 parent 中创建回调函数。
您将函数传递给 child 小部件。
一旦触发,将在 parent 内执行一个函数。 child 只知道它必须触发函数,但所有的逻辑都对它隐藏了。
好的,我想说得更具体一些。我的目标是将我的部分代码 细分为单独的小部件 以便主树尽可能保持干净。
在下面的示例中,我在 StatefulWidget 中有一个 主树。我已经成功地将带有按钮 的容器转换成它自己的带有Extract to Widget 的小部件。按钮的 setState 通过 constructor.
起作用现在我想对第二个装有滑块的容器做同样的事情。但是我不知道如何使用构造函数 处理 Slider onChanged setState,因为 setState 在提取的 Widget 中不起作用。
这是代码示例,工作按钮作为提取的小部件,滑块仍在主树中。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyStfl(),
);
}
}
class MyStfl extends StatefulWidget {
@override
_MyStflState createState() => _MyStflState();
}
class _MyStflState extends State<MyStfl> {
double sliderPos = 0.0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: BoxDecoration(
color: Color(0x80061A28),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: MyCardA(
aktion: () {
setState(() {
print('Button Pressed');
});
},
),
),
Expanded(
child: Container(
child: Slider(
divisions: 48,
value: sliderPos,
min: 0.0,
max: 24.0,
onChanged: (double newValue) {
setState(
() {
sliderPos = double.parse(newValue.toStringAsFixed(1));
print(sliderPos);
},
);
},
),
),
),
],
),
),
);
}
}
class MyCardA extends StatelessWidget {
MyCardA({this.aktion});
final Function aktion;
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(20.0),
padding: EdgeInsets.all(20.0),
color: Color(0x80125889),
child: GestureDetector(
onTap: aktion,
child: Text(
'MY BUTTON',
style: TextStyle(
color: Color(0xFF3D3939),
fontSize: 22.0,
),
),
),
);
}
}
首先,您要在 CardA
组件中更改一件事。不要将 aktion
参数键入 Function
(这非常通用),您应该给它一个类型 void Function()
,说:它是一个 return 什么都没有的函数(空白)。这就是 GestureDetector
的 onTap
参数所期望的。传递任何其他类型的函数不是您想要做的事情,因为它会破坏您的应用程序。键入参数时尽可能具体。您可以将此 void Function()
类型缩短为 VoidCallback
。都是一样的。
我也做了参数required
。这不是必需的,但它是你想要的(我认为)。如果您希望能够发出此参数,请删除 required
关键字并将您的 aktion
键入 void Function()?
。 ?
表示您可以传递 void Function()
或 null
.
class MyCardA extends StatelessWidget {
MyCardA({required this.aktion});
final void Function() aktion;
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(20.0),
padding: EdgeInsets.all(20.0),
color: Color(0x80125889),
child: GestureDetector(
onTap: aktion,
child: Text(
'MY BUTTON',
style: TextStyle(
color: Color(0xFF3D3939),
fontSize: 22.0,
),
),
),
);
}
}
对于'MyCardB',您需要设置一个带有参数的回调函数。有点复杂。
一个Slider
组件有一个onChanged
参数,当滑块位置改变时触发。这为您提供了一个 double
(新位置)并允许您使用它做一些事情。这被键入为 void Function(double)
。我们有一个函数获取一个 double
作为参数,return 什么都没有 (void
).
您可以在下面的自定义组件中看到它的外观。
class MyCardB extends StatelessWidget {
const MyCardB({
required this.sliderPos,
required this.onChanged,
});
final double sliderPos;
final void Function(double) onChanged;
@override
Widget build(BuildContext context) {
return Container(
child: Slider(
divisions: 48,
value: sliderPos,
min: 0.0,
max: 24.0,
onChanged: onChanged,
),
);
}
}
然后您在主组件中使用这个新组件,如下所示。
Expanded(
child: MyCardB(
sliderPos: sliderPos,
onChanged: (double newValue) {
setState(
() {
sliderPos = double.parse(newValue.toStringAsFixed(1));
},
);
},
),
),
长话短说,您想利用 callback functions
。如果您不熟悉它们,我强烈建议您仔细阅读它们,它们非常重要。正如您正确注意到的那样,您无法执行 child 小部件内的逻辑;您想将其保留在 parent 中。您可以通过创建这些回调函数来管理它。
您在 parent 中创建回调函数。 您将函数传递给 child 小部件。 一旦触发,将在 parent 内执行一个函数。 child 只知道它必须触发函数,但所有的逻辑都对它隐藏了。