let cid = "channel-id"
let channelVC = ChatChannelVC()
channelVC.channelController = ChatClient.shared.channelController(for: cid)
let navVC = UINavigationController(rootViewController: channelVC)
present(navVC, animated: true, completion: nil)
Channel
The ChatChannelVC
is the component presented when a channel is selected from the channel list. This component is responsible to display the messages from a channel, as well as creating new messages for the same channel.
The following diagram shows the components hierarchy of ChatChannelVC
:
Overview
ChatChannelHeaderView
is responsible to display the channel information in thenavigationItem.titleView
.ChatMessageListVC
is the component that handles the rendering of the messages.ComposerVC
is the component that handles the creation of new messages.
Usage
By default, the ChatChannelVC
is created when a channel is selected in the ChatChannelListVC
. But in case you want to create it programmatically, you can use the following code:
In this section we are going to use ChatClient
as a singleton, you can find more information about that here
UI Customization
You can customize how the ChatChannelVC
looks by subclassing it and swapping the component in Components
configuration in case you are using the ChatChannelListVC
:
Components.default.channelVC = CustomChatChannelVC.self
You can find more information on how the components configuration works here.
Keep in mind this component is only responsible for composing the ChatChannelHeaderView
, ChatMessageListVC
and ChatMessageComposerVC
components together. In case you want to customize the rendering of the messages, you should read the Message documentation.
Channel Avatar Size
It is really easy to change the channel avatar size displayed by default in the navigationItem.rightBarButtonItem
. The only thing that is needed is to override the channelAvatarSize
property, like this:
class CustomChatChannelVC: ChatChannelVC {
override var channelAvatarSize: CGSize {
CGSize(width: 40, height: 40)
}
}
Layout Customization
Like with any Stream’s component, you can customize the layout of the ChatChannelVC
by overriding the setUpLayout()
function. In the following example, we add a video player on top of the message list to replicate a live stream event use case.
import AVFoundation
class CustomChatChannelVC: ChatChannelVC {
let url = URL(
string: "https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_adv_example_hevc/master.m3u8"
)!
lazy var videoView: UIView = UIView()
lazy var videoPlayer: AVPlayer = {
let asset = AVAsset(url: url)
let playerItem = AVPlayerItem(asset: asset)
return AVPlayer(playerItem: playerItem)
}()
lazy var playerLayer: AVPlayerLayer = {
AVPlayerLayer(player: videoPlayer)
}()
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
playerLayer.frame = videoView.bounds
playerLayer.videoGravity = .resizeAspect
}
override func setUp() {
super.setUp()
videoPlayer.play()
}
override func setUpLayout() {
super.setUpLayout()
view.addSubview(videoView)
videoView.layer.addSublayer(playerLayer)
videoView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
videoView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
videoView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
videoView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
videoView.bottomAnchor.constraint(equalTo: messageListVC.view.topAnchor),
videoView.heightAnchor.constraint(equalTo: view.widthAnchor, multiplier: 9/16)
])
}
}
Result:
Before | After |
---|---|
Channel Query
When creating a ChannelController
for the ChatChannelVC
you can provide ChannelQuery
different from the one used by default. The ChannelQuery
contains the query parameters for fetching the channel from Stream’s backend. It has the following initializer:
public init(
cid: ChannelId,
pageSize: Int? = .messagesPageSize,
paginationParameter: PaginationParameter? = nil,
membersLimit: Int? = nil,
watchersLimit: Int? = nil
)
PageSize
The page size is used to specify how many messages the channel will fetch initially and per page. It is set to 25
by default.
PaginationParameter
The pagination parameter can be used to filter specific messages, like for example, to fetch messages only after or before a certain message. Example:
// Fetch messages after the message with id: "message-id-1"
PaginationParameter.greaterThan("message-id-1")
// Fetch messages before the message with id: "message-id-2"
PaginationParameter.lessThan("message-id-2")
MembersLimit
This argument is used to specify the maximum number of members to be fetched along with the channel info.
WatchersLimit
This argument is used to specify the maximum number of watchers to be fetched along with the channel info.
Properties
content
public var content: ChatChannelController
channelController
Controller for observing data changes within the channel.
open var channelController: ChatChannelController!
userSuggestionSearchController
User search controller for suggestion users when typing in the composer.
open lazy var userSuggestionSearchController: ChatUserSearchController
channelAvatarSize
The size of the channel avatar.
open var channelAvatarSize: CGSize
client
public var client: ChatClient
keyboardHandler
Component responsible for setting the correct offset when keyboard frame is changed.
open lazy var keyboardHandler: KeyboardHandler
messageListVC
The message list component responsible to render the messages.
open lazy var messageListVC: ChatMessageListVC
messageComposerVC
Controller that handles the composer view
open private(set) lazy var messageComposerVC
headerView
Header View
open private(set) lazy var headerView: ChatChannelHeaderView = components
.channelHeaderView.init()
.withoutAutoresizingMaskConstraints
channelAvatarView
View for displaying the channel image in the navigation bar.
open private(set) lazy var channelAvatarView = components
.channelAvatarView.init()
.withoutAutoresizingMaskConstraints
Methods
setUp()
override open func setUp()
setUpLayout()
override open func setUpLayout()
viewDidAppear(_:)
override open func viewDidAppear(_ animated: Bool)
viewDidDisappear(_:)
override open func viewDidDisappear(_ animated: Bool)
channel(for:)
open func channel(for vc: ChatMessageListVC) -> ChatChannel?
numberOfMessages(in:)
open func numberOfMessages(in vc: ChatMessageListVC) -> Int
chatMessageListVC(_:messageAt:)
open func chatMessageListVC(_ vc: ChatMessageListVC, messageAt indexPath: IndexPath) -> ChatMessage?
chatMessageListVC(_:messageLayoutOptionsAt:)
open func chatMessageListVC(
_ vc: ChatMessageListVC,
messageLayoutOptionsAt indexPath: IndexPath
) -> ChatMessageLayoutOptions
chatMessageListVC(_:willDisplayMessageAt:)
open func chatMessageListVC(
_ vc: ChatMessageListVC,
willDisplayMessageAt indexPath: IndexPath
)
chatMessageListVC(_:didTapOnAction:for:)
open func chatMessageListVC(
_ vc: ChatMessageListVC,
didTapOnAction actionItem: ChatMessageActionItem,
for message: ChatMessage
)
chatMessageListVC(_:scrollViewDidScroll:)
open func chatMessageListVC(_ vc: ChatMessageListVC, scrollViewDidScroll scrollView: UIScrollView)
channelController(_:didUpdateMessages:)
open func channelController(
_ channelController: ChatChannelController,
didUpdateMessages changes: [ListChange<ChatMessage>]
)
channelController(_:didUpdateChannel:)
open func channelController(
_ channelController: ChatChannelController,
didUpdateChannel channel: EntityChange<ChatChannel>
)
channelController(_:didChangeTypingUsers:)
open func channelController(
_ channelController: ChatChannelController,
didChangeTypingUsers typingUsers: Set<ChatUser>
)
- Overview
- Usage
- UI Customization
- Channel Query
- Properties
- Methods
- setUp()
- setUpLayout()
- viewDidAppear(_:)
- viewDidDisappear(_:)
- channel(for:)
- numberOfMessages(in:)
- chatMessageListVC(_:messageAt:)
- chatMessageListVC(_:messageLayoutOptionsAt:)
- chatMessageListVC(_:willDisplayMessageAt:)
- chatMessageListVC(_:didTapOnAction:for:)
- chatMessageListVC(_:scrollViewDidScroll:)
- channelController(_:didUpdateMessages:)
- channelController(_:didUpdateChannel:)
- channelController(_:didChangeTypingUsers:)