ChatMessageLayoutOptionsResolver

The ChatMessageLayoutOptionsResolver object is responsible for assigning layout options to a message in a specific position inside a list. Layout options are stored in the ChatMessageLayoutOptions struct type.

Layout options are used by the message view to determining how the message should be rendered (for example render the message with its reactions, message is leading a group of messages, …).

The SDK comes with a built-in resolver which follows the layout rules set by Stream Chat design, this can be customized by writing your own resolver.

Customization

You can change how your messages are rendered by the message view component by selecting your own set of layout options. For instance, StreamChat groups messages by user and shows the avatar and user name at the end of the group. If in your application you want the avatar to be repeated for all messages (like YouTube does) you need to implement your own ChatMessageLayoutOptionsResolver class and register it.

import StreamChat
import StreamChatUI
import UIKit

final class YTMessageLayoutOptionsResolver: ChatMessageLayoutOptionsResolver {
    override func optionsForMessage(
        at indexPath: IndexPath,
        in channel: ChatChannel,
        with messages: AnyRandomAccessCollection<ChatMessage>,
        appearance: Appearance
    ) -> ChatMessageLayoutOptions {
        var options = super.optionsForMessage(at: indexPath, in: channel, with: messages, appearance: appearance)

        // Remove the message options that are not needed in our case
        options.remove([
            .flipped,
            .bubble,
            .timestamp,
            .avatar,
            .avatarSizePadding,
            .authorName,
            .threadInfo,
            .reactions,
            .onlyVisibleForYouIndicator,
            .errorIndicator
        ])

        // Always show the avatar, timestamp and author name for each message
        options.insert([.avatar, .timestamp, .authorName])

        return options
    }
}

You can swap the built-in resolver with your own by setting Components.default.channelContentView to your own view type.

Components.default.messageLayoutOptionsResolver = YTMessageLayoutOptionsResolver()

You can find more information on how the components configuration works here.

ChatMessageLayoutOptions

Describes the layout for a message based on its content and position in the message list. Views rendering a message should use this struct to determine how a message should be rendered.

Properties

rawValue

public let rawValue: Int

flipped

If set all the content will have trailing alignment. By default, the message sent by the current user is flipped.

static let flipped

bubble

If set the message content will be wrapped into a bubble.

static let bubble

continuousBubble

If set the message bubble will not have a tail (rendered by default as a non rounded corner)

static let continuousBubble

avatarSizePadding

If set the message content will have an offset (from the trailing edge if flipped is set otherwise from leading) equal to the avatar size.

static let avatarSizePadding

avatar

If set the message author avatar will be shown.

static let avatar

timestamp

If set the message timestamp will be shown.

static let timestamp

authorName

If set the message author name will be shown in metadata.

static let authorName

text

If set the message text content will be shown.

static let text

quotedMessage

If set the message quoted by the current message will be shown.

static let quotedMessage

threadInfo

If set the message thread replies information will be shown.

static let threadInfo

errorIndicator

If set the error indicator will be shown.

static let errorIndicator

reactions

If set the reactions added to the message will be shown.

static let reactions

onlyVisibleForYouIndicator

If set the indicator saying that the message is visible for current user only will be shown.

static let onlyVisibleForYouIndicator

centered

If set all the content will have centered alignment. By default, the system messages are centered.

static let centered

flipped and centered are mutually exclusive. Only one of these two should be used at a time. If both are specified in the options, centered is prioritized

description

Returns all options the current option set consists of separated by - character.

public var description: String

Examples

Left-aligning All Messages

By default Stream Chat aligns messages from other users on the left and messages from other users on the right, you can left-align all messages by creating your custom left-aligned MessageLayoutOptionsResolver like this:

class LeftAlignedMessageLayoutOptionsResolver: ChatMessageLayoutOptionsResolver {
    override func optionsForMessage(at indexPath: IndexPath, in channel: ChatChannel, with messages: AnyRandomAccessCollection<ChatMessage>, appearance: Appearance) -> ChatMessageLayoutOptions {
        // Get options for the message at given indexpath to change it.
        var options = super.optionsForMessage(at: indexPath, in: channel, with: messages, appearance: appearance)
        // First it's needed to disable the flipping of sides when messages is sent from current user
        options.remove(.flipped)
        // After that we need to ensure that for current user there will be avatar included in the message.
        options.insert(.avatar)
        // If you want, you can include the author name for the message as well.
        options.insert(.authorName)
        return options
    }
}
Components.default.messageLayoutOptionsResolver = LeftAlignedMessageLayoutOptionsResolver()
Default alignmentLeft-side alignment
Chat with default message alignment
Chat with left-only alignment

Hiding Message Bubble

If you need to hide the bubbles, consider implementing a custom subclass of MessageLayoutOptionsResolver and then remove the bubble option.

class NoBubblesMessageLayoutOptionsResolver: ChatMessageLayoutOptionsResolver {
    override func optionsForMessage(at indexPath: IndexPath, in channel: ChatChannel, with messages: AnyRandomAccessCollection<ChatMessage>, appearance: Appearance) -> ChatMessageLayoutOptions {
        // Get options for the message at given indexPath to change it.
        var options = super.optionsForMessage(at: indexPath, in: channel, with: messages, appearance: appearance)
        options.remove(.bubble)
        return options
    }
}
Components.default.messageLayoutOptionsResolver = NoBubblesMessageLayoutOptionsResolver()
visible bubbleshidden bubbles
Chat with default message alignment
Chat with left-only alignment

Disabling Message Groups

The default behaviour of ChatMessageLayoutOptionsResolver is to check whether messages are grouped or not. The isLastInSequence property enables this operation when grouping messages.


class NotGroupedMessageLayoutOptionsResolver: ChatMessageLayoutOptionsResolver {
    override func optionsForMessage(at indexPath: IndexPath, in channel: ChatChannel, with messages: AnyRandomAccessCollection<ChatMessage>, appearance: Appearance) -> ChatMessageLayoutOptions {
        // Get options for the message at given indexPath to change it.
        var options = super.optionsForMessage(at: indexPath, in: channel, with: messages, appearance: appearance)

        options.insert(.continuousBubble)
        options.insert(.timestamp)
        options.insert(.avatar)

        let messageIndex = messages.index(messages.startIndex, offsetBy: indexPath.item)
        let message = messages[messageIndex]

        // Let's add authorName to the message when it's not send by current user.
        if !message.isSentByCurrentUser && !channel.isDirectMessageChannel {
            options.insert(.authorName)
        }

        return options
    }
}
Components.default.messageLayoutOptionsResolver = NotGroupedMessageLayoutOptionsResolver()
Message groupedMessages separated
Chat with default message alignment
Chat with left-only alignment
© Getstream.io, Inc. All Rights Reserved.