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
}
}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.
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: Intflipped
If set all the content will have trailing alignment. By default, the message sent by the current user is flipped.
static let flippedbubble
If set the message content will be wrapped into a bubble.
static let bubblecontinuousBubble
If set the message bubble will not have a tail (rendered by default as a non rounded corner)
static let continuousBubbleavatarSizePadding
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 avatarSizePaddingavatar
If set the message author avatar will be shown.
static let avatartimestamp
If set the message timestamp will be shown.
static let timestampauthorName
If set the message author name will be shown in metadata.
static let authorNametext
If set the message text content will be shown.
static let textquotedMessage
If set the message quoted by the current message will be shown.
static let quotedMessagethreadInfo
If set the message thread replies information will be shown.
static let threadInfoerrorIndicator
If set the error indicator will be shown.
static let errorIndicatorreactions
If set the reactions added to the message will be shown.
static let reactionsonlyVisibleForYouIndicator
If set the indicator saying that the message is visible for current user only will be shown.
static let onlyVisibleForYouIndicatorcentered
If set all the content will have centered alignment. By default, the system messages are centered.
static let centeredflipped 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: StringExamples
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 alignment | Left-side 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 bubbles | hidden bubbles |
|---|---|
![]() | ![]() |
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 grouped | Messages separated |
|---|---|
![]() | ![]() |




