Home > Blockchain >  How to avoid ListView element overlap in Flutter?
How to avoid ListView element overlap in Flutter?

Time:03-07

I have a chatbot screen that I built with a listview and there is a strange behavior that I don't understand the origin of.

From time to time, some of the elements overlap each other, then if I scroll or change screen and come back they are back to normal. I can't seem to find the problem...

Overlap example 1

Overlap example 2

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

import '../../../app_theme.dart';
import '../../../data/models/models.dart';
import '../../../helpers.dart';
import 'action_message.dart';
import 'conversation_bar.dart';
import 'image_message.dart';
import 'text_message.dart';
import 'typing_indicator.dart';

class ConversationFlow extends StatelessWidget {
  // Max number of messages to show
  final int maxMessages = 50;

  Widget _buildConversationMessage(BuildContext context, message, next) {
    // Detects which message type to build as child
    Widget child = Container();
    if (message.text.isEmpty) {
      return child;
    }
    if (message.attachment == null) {
      child = TextMessage(message: message);
    } else if (message.attachment.type == 'image') {
      child = ImageMessage(message: message);
    }

    // General structure of each message
    var topSpacing = App.size(15, context);
    // Between same speaker messages
    if (next != null && next.speaker == message.speaker) {
      topSpacing = App.size(1.5, context);
    }
    // Last one from conversation
    if (next == null) {
      topSpacing = App.size(10, context);
    }

    return Row(
      mainAxisAlignment: (message.speaker == 'coach') ? MainAxisAlignment.start : MainAxisAlignment.end,
      children: [
        Container(
          constraints: BoxConstraints(
            maxWidth: App.isLandscape(context)
                ? MediaQuery.of(context).size.width * 0.42
                : MediaQuery.of(context).size.width * 0.7,
          ),
          padding: EdgeInsets.symmetric(
            vertical: App.size(8, context),
            horizontal: App.size(10, context),
          ),
          margin: EdgeInsets.only(
            left: (message.speaker == 'coach') ? App.margin(context) : 0,
            top: topSpacing,
            right: (message.speaker == 'coach') ? 0 : App.margin(context),
          ),
          decoration: BoxDecoration(
            color: (message.speaker == 'coach') ? AppTheme.colorGrey[100] : AppTheme.colorAccent,
            borderRadius: BorderRadius.circular(App.radius()),
          ),
          child: child,
        ),
        (message.speaker == 'coach' && message.action != null) ? ActionMessage(action: message.action) : Container(),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return StoreConnector(
      converter: (Store<AppState> store) => store.state.bot,
      builder: (BuildContext context, Bot bot) {
        int itemsCount = bot.conversation.isNotEmpty
            ? bot.conversation.length > maxMessages
                ? maxMessages
                : bot.conversation.length   2
            : 1;

        return Align(
          alignment: Alignment.bottomCenter,
          child: ListView.builder(
            shrinkWrap: true,
            reverse: true,
            scrollDirection: Axis.vertical,
            physics: BouncingScrollPhysics(),
            itemCount: itemsCount,
            itemBuilder: (BuildContext context, int index) {
              if (index == 0) {
                return ConversationBar();
              }

              // Typing indicator Row
              if (index == 1) {
                return bot.typing ? TypingIndicator() : Container();
              }

              // Correct Typing index shift
              index = index - 2;

              // Reduces opacity as conversation fades away like memories
              double opacity = 1.0;
              (index > maxMessages - 10) ? opacity = 1.0 - ((index - maxMessages   10) * 0.1) : 0.0;
              if (opacity < 0.0) {
                opacity = 0.0;
              } else if (opacity > 1.0) {
                opacity = 1.0;
              }
              if (index < maxMessages) {
                // Conversation bubbles
                return Opacity(
                  opacity: opacity,
                  child: _buildConversationMessage(
                    context,
                    bot.conversation[index],
                    bot.conversation.asMap().containsKey(index   1) ? bot.conversation[index   1] : null,
                  ),
                );
              }

              return Container();
            },
          ),
        );
      },
    );
  }
}

Any idea of what could cause this?

CodePudding user response:

apply itemExtent: value into Listview.builder

CodePudding user response:

Use readmore package if you have different size and wrap your text into ReadMoreText

ReadMoreText(
      'your message',
      trimLines: 2,
      trimMode: TrimMode.Line,
      trimCollapsedText: 'Read more',
      trimExpandedText: 'Read less',
),

use trimLines for line of text you want to show

  • Related