Add customizable accessoryView besides messageContainer

This commit is contained in:
Shawn Gong
2018-06-02 02:10:51 -07:00
parent 46bebecb6e
commit 9c23282d07
6 changed files with 95 additions and 2 deletions
@@ -180,14 +180,17 @@ UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
case .text, .attributedText, .emoji:
let cell = messagesCollectionView.dequeueReusableCell(TextMessageCell.self, for: indexPath)
cell.configure(with: message, at: indexPath, and: messagesCollectionView)
messagesDataSource.configCell(cell, for: message, at: indexPath)
return cell
case .photo, .video:
let cell = messagesCollectionView.dequeueReusableCell(MediaMessageCell.self, for: indexPath)
cell.configure(with: message, at: indexPath, and: messagesCollectionView)
messagesDataSource.configCell(cell, for: message, at: indexPath)
return cell
case .location:
let cell = messagesCollectionView.dequeueReusableCell(LocationMessageCell.self, for: indexPath)
cell.configure(with: message, at: indexPath, and: messagesCollectionView)
messagesDataSource.configCell(cell, for: message, at: indexPath)
return cell
case .custom:
fatalError(MessageKitError.customDataUnresolvedCell)
+20 -1
View File
@@ -68,6 +68,9 @@ open class MessageSizeCalculator: CellSizeCalculator {
attributes.messageBottomLabelAlignment = messageBottomLabelAlignment(for: message)
attributes.messageBottomLabelSize = messageBottomLabelSize(for: message, at: indexPath)
attributes.accessoryViewSize = accessoryViewSize(for: message)
attributes.accessoryViewPadding = accessoryViewPadding(for: message)
}
open override func sizeForItem(at indexPath: IndexPath) -> CGSize {
@@ -185,6 +188,20 @@ open class MessageSizeCalculator: CellSizeCalculator {
return isFromCurrentSender ? outgoingMessageBottomLabelAlignment : incomingMessageBottomLabelAlignment
}
// MARK: - Accessory View
public func accessoryViewSize(for message: MessageType) -> CGSize {
let layoutDelegate = messagesLayout.messagesLayoutDelegate
let collectionView = messagesLayout.messagesCollectionView
return layoutDelegate.accessoryViewSize(for: message, in: collectionView)
}
public func accessoryViewPadding(for message: MessageType) -> UIEdgeInsets {
let layoutDelegate = messagesLayout.messagesLayoutDelegate
let collectionView = messagesLayout.messagesCollectionView
return layoutDelegate.accessoryViewPadding(for: message, in: collectionView)
}
// MARK: - MessageContainer
public func messageContainerPadding(for message: MessageType) -> UIEdgeInsets {
@@ -201,7 +218,9 @@ open class MessageSizeCalculator: CellSizeCalculator {
open func messageContainerMaxWidth(for message: MessageType) -> CGFloat {
let avatarWidth = avatarSize(for: message).width
let messagePadding = messageContainerPadding(for: message)
return messagesLayout.itemWidth - avatarWidth - messagePadding.horizontal
let accessoryWidth = accessoryViewSize(for: message).width
let accessoryPadding = accessoryViewPadding(for: message)
return messagesLayout.itemWidth - avatarWidth - messagePadding.horizontal - accessoryWidth - accessoryPadding.horizontal
}
// MARK: - Helpers
@@ -46,6 +46,9 @@ open class MessagesCollectionViewLayoutAttributes: UICollectionViewLayoutAttribu
public var messageBottomLabelAlignment = LabelAlignment(textAlignment: .center, textInsets: .zero)
public var messageBottomLabelSize: CGSize = .zero
public var accessoryViewSize: CGSize = .zero
public var accessoryViewPadding: UIEdgeInsets = .zero
// MARK: - Methods
open override func copy(with zone: NSZone? = nil) -> Any {
@@ -63,6 +66,8 @@ open class MessagesCollectionViewLayoutAttributes: UICollectionViewLayoutAttribu
copy.messageTopLabelSize = messageTopLabelSize
copy.messageBottomLabelAlignment = messageBottomLabelAlignment
copy.messageBottomLabelSize = messageBottomLabelSize
copy.accessoryViewSize = accessoryViewSize
copy.accessoryViewPadding = accessoryViewPadding
return copy
// swiftlint:enable force_cast
}
@@ -82,6 +87,8 @@ open class MessagesCollectionViewLayoutAttributes: UICollectionViewLayoutAttribu
&& attributes.messageTopLabelSize == messageTopLabelSize
&& attributes.messageBottomLabelAlignment == messageBottomLabelAlignment
&& attributes.messageBottomLabelSize == messageBottomLabelSize
&& attributes.accessoryViewSize == accessoryViewSize
&& attributes.accessoryViewPadding == accessoryViewPadding
} else {
return false
}
@@ -93,6 +93,14 @@ public protocol MessagesDataSource: AnyObject {
/// The default value returned by this method is `nil`.
func messageBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString?
/// Provide a chance to config a cell before it's presented. e.g. to customize the accessoryView.
///
/// - Parameters:
/// - cell: The `MessageContentCell` that can be configured.
/// - message: The `MessageType` that will be displayed by this cell.
/// - indexPath: The `IndexPath` of the cell.
///
func configCell(_ cell: MessageContentCell, for message: MessageType, at indexPath: IndexPath)
}
public extension MessagesDataSource {
@@ -117,4 +125,5 @@ public extension MessagesDataSource {
return nil
}
func configCell(_ cell: MessageCollectionViewCell, for message: MessageType, at indexPath: IndexPath) {}
}
@@ -81,6 +81,25 @@ public protocol MessagesLayoutDelegate: AnyObject {
/// The default value returned by this method is zero.
func messageBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat
/// Specifies the size for the `MessageContentCell`'s accessory view.
///
/// - Parameters:
/// - message: The `MessageType` that will be displayed for this cell.
/// - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
///
/// - Note:
/// The default value returned by this method is zero.
func accessoryViewSize(for message: MessageType, in messagesCollectionView: MessagesCollectionView) -> CGSize
/// Specifies the padding for the `MessageContentCell`'s accessory view.
///
/// - Parameters:
/// - message: The `MessageType` that will be displayed for this cell.
/// - messagesCollectionView: The `MessagesCollectionView` in which this cell will be displayed.
///
/// - Note:
/// The default value returned by this method is zero.
func accessoryViewPadding(for message: MessageType, in messagesCollectionView: MessagesCollectionView) -> UIEdgeInsets
}
public extension MessagesLayoutDelegate {
@@ -104,4 +123,12 @@ public extension MessagesLayoutDelegate {
func messageBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
return 0
}
func accessoryViewSize(for message: MessageType, in messagesCollectionView: MessagesCollectionView) -> CGSize {
return .zero
}
func accessoryViewPadding(for message: MessageType, in messagesCollectionView: MessagesCollectionView) -> UIEdgeInsets {
return .zero
}
}
+29 -1
View File
@@ -60,6 +60,9 @@ open class MessageContentCell: MessageCollectionViewCell {
return label
}()
// Should only add customized subviews - don't change accessoryView itself.
open var accessoryView: UIView = .init()
/// The `MessageCellDelegate` for the cell.
open weak var delegate: MessageCellDelegate?
@@ -74,6 +77,7 @@ open class MessageContentCell: MessageCollectionViewCell {
}
open func setupSubviews() {
contentView.addSubview(accessoryView)
contentView.addSubview(cellTopLabel)
contentView.addSubview(messageTopLabel)
contentView.addSubview(messageBottomLabel)
@@ -86,6 +90,9 @@ open class MessageContentCell: MessageCollectionViewCell {
cellTopLabel.text = nil
messageTopLabel.text = nil
messageBottomLabel.text = nil
for view in accessoryView.subviews {
view.removeFromSuperview()
}
}
// MARK: - Configuration
@@ -99,6 +106,7 @@ open class MessageContentCell: MessageCollectionViewCell {
layoutCellTopLabel(with: attributes)
layoutMessageTopLabel(with: attributes)
layoutAvatarView(with: attributes)
layoutAccessoryView(with: attributes)
}
/// Used to configure the cell.
@@ -270,5 +278,25 @@ open class MessageContentCell: MessageCollectionViewCell {
messageBottomLabel.frame = CGRect(origin: origin, size: attributes.messageBottomLabelSize)
}
/// Positions the cell's accessory view.
/// - attributes: The `MessagesCollectionViewLayoutAttributes` for the cell.
open func layoutAccessoryView(with attributes: MessagesCollectionViewLayoutAttributes) {
guard attributes.accessoryViewSize != .zero else { return }
let y = (bounds.height - attributes.accessoryViewSize.height) / 2
var origin = CGPoint(x: 0, y: y)
// Accessory view is always on the opposite side of avatar
switch attributes.avatarPosition.horizontal {
case .cellLeading:
origin.x = messageContainerView.frame.maxX + attributes.accessoryViewPadding.left
case .cellTrailing:
origin.x = messageContainerView.frame.minX - attributes.accessoryViewPadding.right - attributes.accessoryViewSize.width
case .natural:
fatalError(MessageKitError.avatarPositionUnresolved)
}
accessoryView.frame = CGRect(origin: origin, size: attributes.accessoryViewSize)
}
}