0

I'm currently working on an application that receives data from a stream and updates a ListView in real-time. The data from the stream is used to build list items, and the content of the current item can change while the stream is active.

Here's the behavior I'm aiming for:

New items should appear at the bottom of the ListView. The ListView should automatically scroll to keep the bottom of the current item in the viewport while it's being updated. I've tried using ScrollController and calling animateTo on it every time the stream updates, but that didn't work as expected. The scroll position seems to be tied to the item index and not its content, so the viewport doesn't always show the bottom of the current item while it's being updated.

Is there a way to achieve this in Flutter, considering the specifics of ListView and the nature of the data stream? Any guidance would be greatly appreciated.

Here's a simplified version of my current code for reference:

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

  @override
  Widget build(BuildContext context) {
    return GetBuilder<OpenAIChatController>(
      init: OpenAIChatController(),
      builder: (controller) {
        final scrollController = ScrollController();
        // Scroll to the bottom when a new response is added
        ever(controller.responses, (_) {
          SchedulerBinding.instance.addPostFrameCallback((_) {
            if (scrollController.hasClients) {
              scrollController.animateTo(
                scrollController.position.maxScrollExtent,
                duration: const Duration(milliseconds: 500),
                curve: Curves.easeOut,
              );
            }
          });
        });

        return Column(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            Expanded(
              child: ListView.builder(
                controller: scrollController,
                itemCount: controller.responses.length,
                itemBuilder: (context, index) {
                  return SelectionArea(
                    child: MarkdownBody(
                      data: controller.responses[index],
                      styleSheet: MarkdownStyleSheet.fromTheme(Theme.of(context)).copyWith(
                        p: Theme.of(context).textTheme.bodyLarge?.apply(
                          color: Colors.white,
                          fontSizeFactor: 1.3,
                        ),
                        code: const TextStyle(
                          fontFamily: 'RobotoMono',
                          fontWeight: FontWeight.bold,
                          fontSize: 18.0,
                        ),
                      ),
                    ),
                  );
                },
              ),
            ),
          ],
        );
      },
    );
  }
}

Thank you in advance for your help!

I have tried scrollable_positioned_list package and various ListView parameters like reverse: true. None of these achieve the desired result.

Albina
  • 1,901
  • 3
  • 7
  • 19
JonnyH
  • 358
  • 2
  • 8

0 Answers0