[英]How to use dynamic interval time in Stream.periodic event in Flutter
[英]Flutter: How scroll programmatically and periodic(from stream)?
我有 flutter 小部件。 它是 SingleChildScrollView 與孩子+“中間光標”:
我可以左右滾動這個列表 - cursor 始終保持在中間。 現在我需要以一秒的頻率以編程方式滾動相對於 cursor 的“孩子”。
我嘗試添加一個計時器和一個線程並在我的小部件中處理它。 我還在我的小部件中添加了 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);
}
}
}
您不能從 build 方法中觸發構建,例如setState
。 因此,您可以將任何對setState
的調用包裝為
WidgetsBinding.instance.addPostFrameCallback((_) {
// Your code here
});
為了在構建方法完成后調用幀末尾的代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.