Flutter:从List中删除项目后,ListView不会自动滚动

yk9xbfzb  于 2023-05-01  发布在  Flutter
关注(0)|答案(1)|浏览(137)

我想进行一次聊天,其中只显示最后30条消息,其余的被删除。在我的应用程序中,每秒钟都会有一条评论被添加到聊天中(这是列表视图中的一个列表),如果这个列表大于30个元素,我会删除最后一条消息。
聊天自动滚动到底部,除非我开始从列表中删除元素(当我打印列表时,评论仍然会添加到列表中,只是不会显示在屏幕上)。有人知道为什么吗?
下面是一个简单的应用程序,它与我描述的问题完全相同。

import 'dart:async';
import 'package:flutter/material.dart';

void main() async {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  Timer? timerComments;
  final ScrollController scrollController = ScrollController();
  List<Widget> chat = [
    const Text("comment"),
    const Text("comment"),
    const Text("comment"),
    const Text("comment"),
    const Text("comment"),
    const Text("comment"),
    const Text("comment"),
    const Text("comment"),
    const Text("comment"),
    const Text("comment"),
    const Text("comment"),
    const Text("comment"),
    const Text("comment"),
    const Text("comment"),
    const Text("comment"),
  ];

  @override
  void initState() {

    // every second the chat gets updated
    timerComments = Timer.periodic(const Duration(seconds: 1), (Timer t) {
      chat.add(const Text("comment"));
      if (chat.length >= 30) chat.removeAt(0);
      setState(() {});
      scrollDown();
    });

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: SizedBox(
          width: 300, height: 300,
          child: ListView( // here is the chat
            shrinkWrap: true,
            controller: scrollController,
            children: chat,
          ),
        ),
      ),
    );
  }

  // scroll down animation
  void scrollDown() {
    scrollController.animateTo(
        scrollController.position.maxScrollExtent,
        duration: const Duration(milliseconds: 1000),
        curve: Curves.fastOutSlowIn
    );
  }
}

附加问题:为什么我必须首先初始化列表视图,然后用10条注解填充它,这样它就可以开始滚动了?如果没有评论或评论较少,列表视图不会滚动:(
我尝试了几种不同的setState((){})方法,但都不起作用。

xmakbtuz

xmakbtuz1#

您面临的问题与scrollDown()方法调用和setState()方法调用的计时有关。从聊天列表中删除元素时,调用setState()重建UI,这将从屏幕中删除删除的元素。但是,在完全重新生成UI之前调用scrollDown()方法,这会导致滚动行为不正确。
要修复此问题,可以在完全重建UI后调用scrollDown()方法。一种方法是使用WidgetsBinding类,它允许您注册一个回调,当应用程序准备好绘制框架时将调用该回调。以下是如何修改代码以使用WidgetsBinding:

import 'package:flutter/scheduler.dart';

...

@override
void initState() {
  timerComments = Timer.periodic(const Duration(seconds: 1), (Timer t) {
    chat.add(const Text("comment"));
    if (chat.length >= 30) chat.removeAt(0);
    setState(() {
      // Register a callback that is called after the UI is fully rebuilt.
      SchedulerBinding.instance?.addPostFrameCallback((_) => scrollDown());
    });
  });
  super.initState();
}

在这段代码中,addPostFrameCallback()方法注册了一个回调,在UI完全重建后调用该回调。回调是一个不带参数的VoidCallback,因此您可以传入一个调用scrollDown()的匿名函数。这确保了在UI完全重建后滚动行为是正确的。

相关问题