我有颤动的小部件。它是带有孩子+“中间光标”的SingleChildScrollView:
我可以左右滚动此列表-光标始终停留在中间。现在,我需要以编程方式以一秒钟的频率相对于光标滚动“子级”。
我尝试添加计时器和线程并在我的小部件中对其进行处理。另外,我在小部件中添加了SteamBuilder,但在一帧中出现错误。
我的错误框:
我的正常构架:
此错误在一帧后发生。任何解决此问题的想法-您将非常感谢。
这是我的完整代码:
void main() => //runApp(MyApp());
runApp(StartApp());
class StartApp extends StatefulWidget {
@override
_StartAppState createState() => _StartAppState();
}
class _StartAppState extends State<StartApp> {
StreamController<double> _currentPositionController;
double position = 0;
Timer _progressTimer;
void positionUpdate(Timer timer) {
position += 0.550;
_currentPositionController.add(position);
}
@override
void initState() {
super.initState();
_progressTimer = Timer.periodic(
Duration(milliseconds: 350), positionUpdate);
_currentPositionController = StreamController<double>.broadcast();
}
@override
void dispose() {
_progressTimer?.cancel();
_currentPositionController?.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: TmpPage(currentPosition:_currentPositionController.stream ),
),
);
}
}
这是我的小部件(TmpPage):
import 'package:flutter/material.dart';
import 'dart:ui';
class TmpPage extends StatefulWidget {
final Stream<double> currentPosition;
const TmpPage({Key key, this.currentPosition}) : super(key: key);
@override
_TmpPageState createState() => _TmpPageState();
}
class _TmpPageState extends State<TmpPage> with WidgetsBindingObserver {
double before = 0;
double halfWidth;
double leftPosition;
ScrollController _controller;
@override
void initState() {
WidgetsBinding.instance.addObserver(this);
halfWidth =0;
_controller = ScrollController();
_controller.addListener(_scrollListener);
super.initState();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
_controller.removeListener(_scrollListener);
_controller.dispose();
super.dispose();
}
double width = 0.0;
double height = 0.0;
@override void didChangeMetrics() {
setState(() {
width = window.physicalSize.width;
height = window.physicalSize.height;
halfWidth = window.physicalSize.width / 2;
//halfWidth = (MediaQuery.of(context).size.width) / 2;
leftPosition = halfWidth;
});
}
@override
Widget build(BuildContext context) {
return _getBody(context);
}
Widget _getBody(context) {
if(halfWidth ==0)
halfWidth = (MediaQuery.of(context).size.width) / 2;
if (before == 0)
leftPosition = halfWidth;
return StreamBuilder<double>(
stream: widget.currentPosition,
builder: (context, snapshot) {
if(snapshot.data !=null && _controller.hasClients){
_controller.jumpTo(snapshot.data);
}
return NotificationListener<ScrollNotification>(
onNotification: (scrollNotification) {
if (scrollNotification is ScrollUpdateNotification) {
var m = scrollNotification.metrics;
before = m.extentBefore;
setState(() {
leftPosition = before;
});
return false;
}
return false;
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SingleChildScrollView(
controller: _controller,
scrollDirection: Axis.horizontal,
child: Row(
children: <Widget>[
SizedBox(
width: halfWidth,
),
Stack(
children: <Widget>[
Row(
children: List.generate(
30,
(i) => Padding(
padding: const EdgeInsets.all(2.0),
child: new Container(
height: 42.0,
width: 42.0,
color: _getColor(i),
),
)).toList(),
),
Positioned(
left: leftPosition,
top: 0,
bottom: 0,
child: Container(
color: Colors.red,
width: 2,
),
),
],
),
SizedBox(
width: halfWidth,
),
],
)),
],
),
);
}
);
}
Color _getColor(int i) {
if(i<10)
return Colors.blueGrey;
if(i<20)
return Colors.orange;
if(i<30)
return Colors.lightBlueAccent;
else
return Colors.green;
}
void _scrollListener() {
if (_controller.offset >= _controller.position.maxScrollExtent &&
!_controller.position.outOfRange) {
print('end');
_controller.jumpTo(_controller.offset - 1);
}
if (_controller.offset <= _controller.position.minScrollExtent &&
!_controller.position.outOfRange) {
print('start');
_controller.jumpTo(_controller.offset + 1);
}
}
}
您无法像在setState
中那样从build方法内部触发构建。因此,您可以使用
setState
的所有调用WidgetsBinding.instance.addPostFrameCallback((_) {
// Your code here
});
为了在构建方法完成后在框架的结尾处调用代码。