Flutter:如何以编程方式定期滚动(从流)?

问题描述 投票:0回答:1

我有颤动的小部件。它是带有孩子+“中间光标”的SingleChildScrollView:

“文本”

我可以左右滚动此列表-光标始终停留在中间。现在,我需要以编程方式以一秒钟的频率相对于光标滚动“子级”。

我尝试添加计时器和线程并在我的小部件中对其进行处理。另外,我在小部件中添加了SteamBuilder,但在一帧中出现错误。

我的错误框:

enter image description here

我的正常构架:

enter image description here

此错误在一帧后发生。任何解决此问题的想法-您将非常感谢。

这是我的完整代码:

    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);
    }
  }
}
flutter dart flutter-layout
1个回答
1
投票

您无法像在setState中那样从build方法内部触发构建。因此,您可以使用

包装对setState的所有调用
WidgetsBinding.instance.addPostFrameCallback((_) {
  // Your code here
});

为了在构建方法完成后在框架的结尾处调用代码。

© www.soinside.com 2019 - 2024. All rights reserved.