Skip to content

ChatAnimatedList scrolls to bottom when it becomes scrollable #885

@angelosilvestre

Description

@angelosilvestre

When the ChatAnimatedList transitions from non-scrollable to scrollable, for example, when a message that does not fit the viewport is received, it automatically scrolls to the end. As a result, the user needs to scroll up again to see the beginning of the message.

Steps to reproduce:

  1. Run the sample code
  2. Tap "Add Tall Message"
  3. See the behavior

Expected behavior:
The list should not scroll

Actual behavior:
The list scrolls

Screen.Recording.2026-01-22.at.08.59.33.mov
Code sample
import 'package:flutter/material.dart';
import 'package:flutter_chat_core/flutter_chat_core.dart' as chat_core;
import 'package:flutter_chat_ui/flutter_chat_ui.dart';

void main() {
  runApp(const MinimalReproApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Scroll Bug Repro',
      debugShowCheckedModeBanner: false,
      home: const ChatPage(),
    );
  }
}

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

  @override
  State<ChatPage> createState() => _ChatPageState();
}

class _ChatPageState extends State<ChatPage> {
  final chat_core.ChatController _chatController = chat_core.InMemoryChatController();
  final _user = const chat_core.User(id: 'user-1');
  final _otherUser = const chat_core.User(id: 'user-2', name: 'Other User');
  int _messageCounter = 0;

  @override
  void initState() {
    super.initState();
    _loadInitialMessages();
  }

  void _loadInitialMessages() {
    _addMessage('Message ${_messageCounter + 1}');
  }

  void _addMessage(String text, {String? authorId}) {
    final message = chat_core.TextMessage(
      createdAt: DateTime.now(),
      id: 'msg-${_messageCounter++}',
      text: text,
      authorId: authorId ?? _user.id,
    );

    setState(() {
      _chatController.insertMessage(message);
    });
  }

  void _addTallMessage() {
    // Create a message with lots of text that will be taller than the viewport
    final tallText = List.generate(70, (i) => 'Line ${i + 1} of a very tall message.')
        .join('\n');

    // Send from the other user to simulate receiving a tall message
    _addMessage(tallText, authorId: _otherUser.id);
  }

  Future<chat_core.User> _resolveUser(String userId) async {
    if (userId == _otherUser.id) {
      return _otherUser;
    }
    return _user;
  }

  late final chat_core.Builders _chatBuilders = chat_core.Builders(
    chatAnimatedListBuilder: (context, itemBuilder) {
      return ChatAnimatedList(
        itemBuilder: itemBuilder,
        shouldScrollToEndWhenAtBottom: false,
        shouldScrollToEndWhenSendingMessage: false,
        initialScrollToEndMode: InitialScrollToEndMode.none,
      );
    },
  );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Scroll Bug Reproduction'),
        actions: [
          TextButton(
            onPressed: _addTallMessage,
            style: TextButton.styleFrom(
              backgroundColor: Colors.red,
            ),
            child: const Text(
              'Add Tall Message',
              style: TextStyle(color: Colors.black),
            ),
          ),
        ],
      ),
      body: Column(
        children: [       
          Expanded(
            child: Chat(
              chatController: _chatController,
              currentUserId: _user.id,
              resolveUser: _resolveUser,
              builders: _chatBuilders,
              theme: chat_core.ChatTheme(
                colors: chat_core.ChatColors(
                  primary: Colors.blue,
                  onPrimary: Colors.white,
                  surface: Colors.white,
                  onSurface: Colors.black,
                  surfaceContainer: Colors.grey.shade100,
                  surfaceContainerLow: Colors.grey.shade50,
                  surfaceContainerHigh: Colors.grey.shade200,
                ),
                typography: chat_core.ChatTypography(
                  bodyLarge: const TextStyle(fontSize: 16),
                  bodyMedium: const TextStyle(fontSize: 14),
                  bodySmall: const TextStyle(fontSize: 12),
                  labelLarge: const TextStyle(fontSize: 16),
                  labelMedium: const TextStyle(fontSize: 14),
                  labelSmall: const TextStyle(fontSize: 12),
                ),
                shape: const BorderRadiusGeometry.only(
                  topLeft: Radius.circular(20),
                  topRight: Radius.circular(20),
                  bottomLeft: Radius.circular(20),
                ),
              ),             
            ),
          ),
        ],
      ),
    );
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions