flutter ScrollController.jumpTo()“ScrollController未附加到任何滚动视图”

5q4ezhmt  于 2023-03-31  发布在  Flutter
关注(0)|答案(6)|浏览(339)

我监听一个PageController来获取位置,然后将其与一个ListView同步。当操纵PageView时,同时也操纵ListView。
示例:https://github.com/Ramotion/cardslider-android
然而,在v0.6.0之后,我得到了一个Assert错误,我的ScrollController没有附加到任何视图。每当有一个流事件触发.jumpTo()方法时,它就会触发。它仍然可以工作,但Assert错误让我抓狂。

[VERBOSE-2:shell.cc(181)] Dart Error: Unhandled exception:
'package:flutter/src/widgets/scroll_controller.dart': Failed assertion: line 169 pos 12: '_positions.isNotEmpty': ScrollController not attached to any scroll views.
#0      _AssertionError._doThrowNew (dart:core/runtime/liberrors_patch.dart:40:39)
#1      _AssertionError._throwNew (dart:core/runtime/liberrors_patch.dart:36:5)
#2      ScrollController.jumpTo (package:flutter/src/widgets/scroll_controller.dart:169:12)
#3      MyTitle.build.<anonymous closure> (file:///Users/lukepighetti/code/when-coin/when_coin_2/lib/screens/rate/widgets/title.dart:19:19)
#4      _RootZone.runUnaryGuarded (dart:async/zone.dart:1314:10)
#5      _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:336:11)
#6      _DelayedData.perform (dart:async/stream_impl.dart:584:14)
#7      _StreamImplEvents.handleNext (dart:async/stream_impl.dart:700:11)
#8      _PendingEvents.schedule.<anonymous closure> (dart:async/stream_impl.dart:660:7)
#9      _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
#10     _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)

如何使用ScrollController.jumpTo()而不遇到此异常?

class MyTitle extends StatelessWidget {
  final List<Category> categories;
  MyTitle({this.categories});

  @override
  Widget build(BuildContext context) {
    final _controller = ScrollController();
    double height = 36.0;
    // double width = MediaQuery.of(context).size.width * 0.8;

    BlocProvider.of(context).page.listen((page) {
      _controller.jumpTo(height * page);
    });

    return Container(
      height: height,
      // width: width,
      child: ListView(
        controller: _controller,
        scrollDirection: Axis.vertical,
        physics: NeverScrollableScrollPhysics(),
        children: categories
            .map((c) => _Title(
                  title: c.title,
                  index: categories.indexOf(c),
                ))
            .toList(),
      ),
    );
  }
}
3bygqnnd

3bygqnnd1#

正如上面的答案所述,当ScrollController还没有附加到ListView或其他ScrollView时,您正在使用它。您可以使用hasClients属性检查这一点。

if (_scrollController.hasClients) {
  await _scrollController.animateTo(
    0.0,
    curve: Curves.easeOut,
    duration: const Duration(milliseconds: 300),
  );
}
cnwbcb6i

cnwbcb6i2#

检查控制器是否有客户端,然后延迟跳转:

if (_scrollController.hasClients) {
      Future.delayed(Duration(milliseconds: 50), () {
        _scrollController?.jumpTo(_scrollController.position.maxScrollExtent);
      });
    }
q0qdq0h2

q0qdq0h23#

问题是你正在重新创建_controller并在每个build上订阅它。控制器必须作为最终的类作用域属性创建一次。此外,你应该使用StatefulWidgetdispose控制器和subsribe在initState方法中进行流式传输。

class MyTitle extends StatefullWidget {
 MyTitle({this.categories});

 final List<Category> categories;

_MyTitleState createState() => _MyTitleState();
}

class _MyTitleState extends State<MyTitle> {
  final _controller = ScrollController(); // <--
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  void initState() {
    super.initState();
    BlocProvider.of(context, listen: false).page.listen((page) {
      if(_constoller.hasClients) {
      _controller.jumpTo(height * page);
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    double height = 36.0;
    // double width = MediaQuery.of(context).size.width * 0.8;

    return Container(
      height: height,
      // width: width,
      child: ListView(
        controller: _controller,
        scrollDirection: Axis.vertical,
        physics: NeverScrollableScrollPhysics(),
        children: categories
            .map((c) => _Title(
                  title: c.title,
                  index: categories.indexOf(c),
                ))
            .toList(),
      ),
    );
  }
}
w1jd8yoj

w1jd8yoj4#

对于需要另一种方法的人,可以使用Flutter After Layout

void initState() {
    super.initState();
    WidgetsBinding.instance
        .addPostFrameCallback((_) => yourFunction(context));
  }

yourFunction将在布局完成后执行。

daupos2t

daupos2t5#

检查控制器没有客户端蚂蚁,然后延迟跳转:

if (!_scrollController.hasClients) {
      Future.delayed(Duration(milliseconds: 50), () {
        _scrollController?.jumpTo(_scrollController.position.maxScrollExtent);
      });
    }
eiee3dmh

eiee3dmh6#

您正在尝试在将scrollController添加到ScrollView(列表视图)之前使用scrollController进行跳转。我们必须在添加到控制器后进行跳转。参考下面的代码。

// task1
 Future.delayed(Duration.zero, () => 
 { // task2
  BlocProvider.of(context).page.listen((page) { _controller.jumpTo(height * page); }); 
 });
// task3

这与DispatchQueue.main.async非常相似,因为持续时间为 * 零 *。执行顺序为task1,task3,task2

相关问题