我是Flutter开发的初学者,遇到了一些问题。我会尽力向我解释。
我有一个滑动条(有状态的自定义窗口小部件)。我想将此小部件集成到我的主视图中,但是我必须更改滑块的值(此值也可以通过轻击手势检测器更改)。
经过网上研究,我尝试了几件事。
例如,使用VerticalSliderState
的吸气剂并访问VerticalSliderState
方法来更改值。
在收到the state is null
错误后,这种方法只起作用了一次,我想我错过了setState()
的抖动概念。
有什么解释吗?谢谢:P
这是我的代码:
有状态的自定义小部件:
import 'package:flutter/material.dart';
class VerticalSlider extends StatefulWidget {
....
final double value;
.....
final void Function(double) onValueChanged;
VerticalSlider({
Key key,
@required this.height,
@required this.width,
this.onValueChanged,
this.value,
....
}) : super(key: key);
VerticalSliderState state;
@override
VerticalSliderState createState(){
state = new VerticalSliderState();
return state ;
}
}
class VerticalSliderState extends State<Vertical Slider>{
.....
double _value;
double _currentHeight;
Widget _movingDecoratedBox;
Widget _fixedDecoratedBox;
void setValue(double value){
_setValue(value, false, widget.height);
}
initState() {
super.initState();
_value = widget.value ?? 5.0;
_currentHeight = _convertValueToHeight();
_movingDecoratedBox = widget.movingBox ?? DecoratedBox(
decoration: BoxDecoration(color: Colors.red)
);
_fixedDecoratedBox = widget.fixedBox ?? DecoratedBox(
decoration: BoxDecoration(color: Colors.grey),
);
}
..........
void _onTapUp(TapUpDetails tapDetails) {
RenderBox renderBox = context.findRenderObject();
var newHeight = widget.height - renderBox.globalToLocal(tapDetails.globalPosition).dy;
var newValue = _convertHeightToValue(newHeight);
setState(() {
_currentHeight = (widget.height/10.5) * (newValue);
_setValue(newValue, true, widget.height);
});
}
void _setValue(double newValue, bool userRequest, double height) {
_value = newValue;
if(userRequest){
widget.onValueChanged(_value);
}
else{
setState(() {
_currentHeight = (height/10.5) * (newValue);
});
}
}
Widget _buildMovingBox() {
return Align(
alignment: Alignment.bottomCenter,
child: SizedBox(
width: widget.width,
height: _currentHeight,
child: _movingDecoratedBox,
),
);
}
..........
@override
Widget build(BuildContext context) {
return GestureDetector(
onTapUp: _onTapUp,
child: Stack(
alignment: AlignmentDirectional.bottomCenter,
children: <Widget>[
_buildFixedBox(),
_buildMovingBox(),
],
),
);
}
我的主视图:
seekBar1 = new VerticalSlider(
height: mediaQueryData.size.height / 2.7,
width: 40.0,
max: 11.0,
min: 0.0,
value: 5.5,
movingBox: new Container(color: Colors.teal),
fixedBox: new Container(color: Colors.grey[200]),
onValueChanged: onValueChanged1,
);
void onValueChanged1(double newValue) {
seekBar2.state.setValue(10-newValue);
print(newValue);
}
答案 0 :(得分:0)
请记住以下几点:
您不想在state
中使用Stateful Widget
变量,
您都不想通过myWidget.state
访问它。让
小部件本身会处理自己的状态。
您得到null
的原因是,当您在自己的计算机上执行setState
时
VerticalSliderState
对象,它将重建您的树,因此,
生成新的更新后的VerticalSliderState
。那意味着你
状态引用现在将为空。
如果您想访问自己州内的某些数据,可以采取
最终回调(例如您的onValueChanged
)的优势或
可以使用Streams。
此外,使用方法返回Widgets
而不是变量,这更正确。
例如,如果您有seekBar2.state.setValue(10-newValue);
,则只想创建一个具有更新值的新seekBar2 = VerticalSlider(updated properties)
,而不要这样做。
答案 1 :(得分:0)
一个解决方案是下面完整示例中的解决方案。滑块小部件将更新主页中的值,并用于设置另一个滑块中的值。
由于您的代码段不完整,我已经编写了一些代码。
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
double _value = 9;
void onValueChanged(double newValue) {
setState(() {
_value = newValue;
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Test"),
),
body: new Center(
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
VerticalSlider(
height: MediaQuery.of(context).size.height / 2.7,
width: 40.0,
max: 11.0,
min: 0.0,
value: _value,
movingBox: new Container(color: Colors.teal),
fixedBox: new Container(color: Colors.grey[200]),
onValueChanged: onValueChanged,
),
SizedBox(
width: 50.0,
),
VerticalSlider(
height: MediaQuery.of(context).size.height / 2.7,
width: 40.0,
max: 11.0,
min: 0.0,
value: _value,
movingBox: new Container(color: Colors.teal),
fixedBox: new Container(color: Colors.grey[200]),
onValueChanged: onValueChanged,
),
],
),
),
);
}
}
class VerticalSlider extends StatefulWidget {
final double height;
final double width;
final double max;
final double min;
final double value;
final Widget movingBox;
final Widget fixedBox;
final void Function(double) onValueChanged;
VerticalSlider({
Key key,
@required this.height,
@required this.width,
this.onValueChanged,
this.value,
this.max,
this.min,
this.movingBox,
this.fixedBox,
}) : super(key: key);
@override
VerticalSliderState createState() {
return VerticalSliderState();
}
}
class VerticalSliderState extends State<VerticalSlider> {
double _value;
double _currentHeight;
@override
void didUpdateWidget(VerticalSlider oldWidget) {
super.didUpdateWidget(oldWidget);
_init();
}
initState() {
super.initState();
_init();
}
void _init() {
_value = widget.value ?? widget.max / 2;
_currentHeight = _convertValueToHeight();
}
double _convertValueToHeight() {
return _value * widget.height / widget.max;
}
double _convertHeightToValue(double height) {
return height * widget.max / widget.height;
}
void _onTapUp(TapUpDetails tapDetails) {
RenderBox renderBox = context.findRenderObject();
var newHeight =
widget.height - renderBox.globalToLocal(tapDetails.globalPosition).dy;
var newValue = _convertHeightToValue(newHeight);
widget.onValueChanged(newValue);
setState(() {
_currentHeight = newHeight;
});
}
Widget _buildMovingBox() {
return Align(
alignment: Alignment.bottomCenter,
child: SizedBox(
width: widget.width,
height: _currentHeight,
child: widget.movingBox ??
DecoratedBox(decoration: BoxDecoration(color: Colors.red)),
),
);
}
Widget _buildFixedBox() {
return Align(
alignment: Alignment.bottomCenter,
child: SizedBox(
width: widget.width / 2,
height: double.infinity,
child: widget.fixedBox ??
DecoratedBox(
decoration: BoxDecoration(color: Colors.grey),
),
),
);
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTapUp: _onTapUp,
child: SizedBox(
width: widget.width,
height: widget.height,
child: Stack(
alignment: AlignmentDirectional.bottomCenter,
children: <Widget>[
_buildFixedBox(),
_buildMovingBox(),
],
),
),
);
}
}