测试已测试 | ✓ |
语言语言 | SwiftSwift |
许可证 | MIT |
发布最后发布 | 2017年3月 |
SwiftSwift 版本 | 3.0 |
SPM支持 SPM | ✗ |
由 David Schechter,Aaron Tainter 维护。
NMessenger 是一个基于 AsyncDisplayKit 并使用 Swift 编写的快速、轻量级消息组件。开发者可以天然实现具有丰富内容组件的 60FPS 滚动和流畅过渡。
内置支持
将 NSPhotoLibraryUsageDescription
和 NSCameraUsageDescription
添加到您的 App Info.plist 中,以指定访问照片库和相机的理由。有关更多详细信息,请参阅 Cocoa 键。
NMessengerViewController
的设备旋转。NMessenger 随附预构建的 NMessengerViewController,该控制器具有一些支持的功能。
发送文本消息。
func sendText(text: String, isIncomingMessage:Bool) -> GeneralMessengerCell
发送带图片的消息。
func sendImage(image: UIImage, isIncomingMessage:Bool) -> GeneralMessengerCell
发送带网络图片的消息。 (使用 AsyncDisplayKit 和 PINCache 懒加载和缓存网络图片)
func sendNetworkImage(imageURL: String, isIncomingMessage:Bool) -> GeneralMessengerCell
可以直接从视图或节点数组中创建包含集合视图的消息。 注意:节点利用 ASDK 的异步渲染功能,将使此组件滚动更加顺畅。
func sendCollectionViewWithViews(views: [UIView], numberOfRows:CGFloat, isIncomingMessage:Bool) -> GeneralMessengerCell
func sendCollectionViewWithNodes(nodes: [ASDisplayNode], numberOfRows:CGFloat, isIncomingMessage:Bool) -> GeneralMessengerCell
单行集合视图
多行集合视图
发送带自定义视图或节点的消息。 注意:节点利用 ASDK 的异步渲染功能,将使此组件滚动更加顺畅。
func sendCustomView(view: UIView, isIncomingMessage:Bool) -> GeneralMessengerCell
func sendCustomNode(node: ASDisplayNode, isIncomingMessage:Bool) -> GeneralMessengerCell
这些函数是为了在网络调用和其他控制器逻辑中重写。
输入指示器表示正在输入传入的消息。默认情况下,这将是消息者中的最后一条消息。
/** Adds an incoming typing indicator to the messenger */
func showTypingIndicator(avatar: ASDisplayNode) -> GeneralMessengerCell
/** Removes a typing indicator from the messenger */
func removeTypingIndicator(indicator: GeneralMessengerCell)
要使用自定义输入栏,您必须子类化 InputBarView
。 InputBarView
遵循 InputBarViewProtocol
@objc public protocol InputBarViewProtocol
{
/* Superview of textInputView - can hold send button and/or attachment button*/
var textInputAreaView: UIView! {get set}
/* UITextView where the user will input the text*/
var textInputView: UITextView! {get set}
//NMessengerViewController where to input is sent to
var controller:NMessengerViewController! {get set}
}
必须创建 textInputAreaView
和 textInputView
,以便 NMessengerViewController
有正确的行为。 controller
由 InputBarView
基类的初始化器设置。
要使用您自定义的输入栏,请在 NMessengerViewController
中重写 func getInputBar()->InputBarView
。
NMessenger 可以添加到任何视图。
self.messengerView = NMessenger(frame: CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height))
messengerView.delegate = self
self.view.addSubview(self.messengerView)
使用 NMessenger,无需管理数据源。只需添加消息并忘记它。
更改和更新消息依赖于引用。这些引用可以通过代理方法传递或在本地存储在类中。
self.delegate.deleteMessageBtnClick(self)
.
.
.
func deleteMessageBtnClick(message: GeneralMessageCell) {
self.messengerView.removeMessage(message, .None)
}
NMessenger 随附一些预构建的气泡类型。《bubble》也可以很容易地子类化来创建新的气泡组件。
SimpleBubble
DefaultBubble
StackedBubble
ImageBubble
- 可以与任何 9 Patch Image 一起使用
通过设置 hasLayerMask = true
,气泡将遮罩其内容。这对图像和其他丰富内容组件很重要。
为了为消息配置自定义气泡,您必须创建一个新的类来实现 BubbleConfigurationProtocol
。
/** Configures a bubble for a ContentNode. Implement this to create your own bubble configuration */
protocol BubbleConfigurationProtocol {
var isMasked: Bool {get set}
/** Create and return a UI color representing an incoming message */
func getIncomingColor() -> UIColor
/** Create and return a UI color representing an outgoing message */
func getOutgoingColor() -> UIColor
/** Create and return a bubble for the ContentNode */
func getBubble() -> Bubble
/** Create and return a bubble that is used by the Message group for Message nodes after the first. This is typically used to "stack" messages */
func getSecondaryBubble() -> Bubble
}
此协议旨在为基本(messageNode)和辅助(messageGroup)气泡类型提供新的气泡类实例。通过更改 var sharedBubbleConfiguration: BubbleConfigurationProtocol
中的 NMessengerViewController
,您可以设置所有新添加消息的配置。
内容节点在 MessageNode
中持有消息内容(气泡内部的所有内容)。
通过子类化 ContentNode
,您可以定义自己的内容。这特别适用于创建不在我们的库存消息套件中的丰富内容组件。或者,您可以初始化带有自己视图或节点的 'CustomContentNode'。
内容节点还可以赋予一个《气泡配置协议》(BubbleConfigurationProtocol)来自定义它们的气泡。
可以通过继承《通用消息单元》(GeneralMessengerCell)来制作任何类型的组件。所有消息单元都扩展了这个对象。
可以使用《消息发送指示器》类轻松地添加时间戳。
let messageTimestamp = MessageSentIndicator()
messageTimestamp.messageSentText = "NOW"
//NMessengerViewController
self.addMessageToMessenger(messageTimestamp)
//NMessenger
messengerView.addMessage(messageTimestamp, scrollsToMessage: false)
可以使用AsyncDisplayKit的《ASImageNode》来设置自定义头像。
let nAvatar = ASImageNode()
nAvatar.image = UIImage(named: "nAvatar")
.
.
.
messageNode.avatarNode = nAvatar
许多消息单元会在头部预取。这在使用UITableView或AsyncDisplayKit功能时并不简单。NMessenger支持即开即用的头部预取。
要使用头部预取功能,请在NMessenger上设置var doesBatchFetch: Bool = true
。NMessengerDelegate也需要由您的控制器实现并设置。
@objc protocol NMessengerDelegate {
/**
Triggered when a load batch content should be called. This method is called on a background thread.
Make sure to add prefetched content with *endBatchFetchWithMessages(messages: [GeneralMessengerCell])**/
optional func batchFetchContent()
/** Returns a newly created loading Indicator that should be used at the top of the messenger */
optional func batchFetchLoadingIndicator()->GeneralMessengerCell
}
所有批量获取网络调用都应该在batchFetchContent
中进行。务必添加您的消息单元,使用endBatchFetchWithMessages(messages: [GeneralMessengerCell])
来结束批量获取。调用此函数将移除加载指示器和批量获取锁。
可以使用消息组堆叠消息并动画头像。与《消息节点》(MessageNode)一样,《消息组》(MessageGroup)扩展自《通用消息单元》(GeneralMessageCell)。区别是,《消息组》持有《消息节点》表而不是《内容节点》。
================
| MessageGroup | -> =============== ===============
================ | MessageNode | -> | ContentNode | (Primary Bubble)
--------------- ===============
| MessageNode | -> | ContentNode | (Secondary Bubble)
--------------- ===============
| MessageNode | -> | ContentNode | (Secondary Bubble)
--------------- ===============
| MessageNode | -> | ContentNode | (Secondary Bubble)
=============== ===============
此外,《消息组》根据表中的位置确定《消息节点》内容的气泡类型。第一条消息的内容将有一个主要气泡,其余的将有一个次要气泡。通常,组中的任何《消息节点》将禁用头像,但保留给《消息组》。
消息组包括一些用于在组中添加、删除和更新《消息节点》的流畅动画。这些可以直接从《消息组》调用,也可以从《NMessenger》添加和删除。注意:这些在《NMessengerViewController》中还没有显示出来
建议从《NMessenger》中删除它们,因为正在删除的《MessageNode》可能是组中的最后一个消息。如果发生这种情况,在《MessageGroup》被删除后,《MessageGroup》将仍然存在。《NMessenger》确保在这种情况下从消息中删除《MessageGroup》。
添加一个《消息节点》。
messageGroup.addMessageToGroup(message: GeneralMessengerCell, completion: (()->Void)?)
删除一个《消息节点》。
messageGroup.removeMessageFromGroup(message: GeneralMessengerCell, completion: (()->Void)?)
使用新的《消息节点》更新现有的《消息节点》。
messageGroup.replaceMessage(message: GeneralMessengerCell, withMessage newMessage: GeneralMessengerCell, completion: (()->Void)?)