如何将 ASTextNode 与 TTTAttributedLabel 一起使用
How can I use ASTextNode with TTTAttributedLabel
我已经构建了一个 ASCellNode
,它运行良好。但是,当我使用传统的 UICollectionViewCell
时,我使用了带链接的 TTTAttributedLabel
。
我不知道如何用 AsyncDisplayKit
复制它
我可以将 TTTAttributedLabel
中的 attriubtedText 分配给 ASTextNode
,但当然它不会保留链接。我怎么能有效地做到这一点。以我的 ASCellNode
.
为例
protocol EmailSentDelegator : class {
func callSegueFromCell(data object: JSON)
}
class EmailCellNode: ASCellNode, TTTAttributedLabelDelegate {
let cardHeaderNode: ASTextNode
var frameSetOrNil: FrameSet?
init(mailData: JSON) {
// Create Nodes
cardHeaderNode = ASTextNode()
super.init()
// Set Up Nodes
cardHeaderNode.attributedString = createAttributedLabel(mailData, self).attributedText
// Build Hierarchy
addSubnode(cardHeaderNode)
}
override func calculateSizeThatFits(constrainedSize: CGSize) -> CGSize {
var cardSize = CGSizeZero
cardSize.width = UIScreen.mainScreen().bounds.size.width - 16
// Measure subnodes
let cardheaderSize = cardHeaderNode.measure(CGSizeMake(cardSize.width - 56, constrainedSize.height))
cardSize.height = max(cardheaderSize.height,40) + subjectLabelSize.height + timeStampSize.height + emailAbstractSize.height + 30
// Calculate frames
frameSetOrNil = FrameSet(node: self, calculatedSize: cardSize)
return cardSize
}
override func layout() {
if let frames = frameSetOrNil {
cardHeaderNode.frame = frames.cardHeaderFrame
}
}
func attributedLabel(label: TTTAttributedLabel!, didSelectLinkWithTransitInformation components: [NSObject : AnyObject]!) {
self.delegate.callSegueFromCell(data: mailData)
}
func createAttributedLabel(mailData: JSON, cell: EmailCellNode) -> TTTAttributedLabel{
let senderName = mailData["From"]["Name"].string!
var recipients:[String] = []
for (key: String, subJson: JSON) in mailData["To"] {
if let recipientName = subJson["Name"].string {
recipients.append(recipientName)
}
}
var cardHeader = TTTAttributedLabel()
cardHeader.setText("")
cardHeader.delegate = cell
cardHeader.userInteractionEnabled = true
// Add sender to attributed string and save range
var attString = NSMutableAttributedString(string: "\(senderName) to")
let senderDictionary:[String:String] = ["sender": senderName]
let rangeSender : NSRange = (attString.string as NSString).rangeOfString(senderName)
// Check if recipients is nil and add undisclosed recipients
if recipients.count == 0 {
attString.appendAttributedString(NSAttributedString(string: " undisclosed recipients"))
let rangeUndisclosed : NSRange = (attString.string as NSString).rangeOfString("undisclosed recipients")
attString.addAttribute(NSFontAttributeName, value: UIFont(name: "SourceSansPro-Semibold", size: 14)!, range: rangeUndisclosed)
attString.addAttribute(NSForegroundColorAttributeName, value: UIColor.grayColor(), range: rangeUndisclosed)
} else {
// Add recipients (first 5) to attributed string and save ranges for each
var index = 0
for recipient in recipients {
if (index == 0) {
attString.appendAttributedString(NSAttributedString(string: " \(recipient)"))
} else if (index == 5){
attString.appendAttributedString(NSAttributedString(string: ", and \(recipients.count - index) other"))
break
} else {
attString.appendAttributedString(NSAttributedString(string: ", \(recipient)"))
}
index = index + 1
}
}
cardHeader.attributedText = attString
// Adding recipients and sender links with recipient object to TTTAttributedLabel
cardHeader.addLinkToTransitInformation(senderDictionary, withRange: rangeSender)
if recipients.count != 0 {
var index = 0
var position = senderName.length + 2
for recipient in recipients {
let recipientDictionary:[String: AnyObject] = ["recipient": recipient,"index": index ]
let rangeRecipient : NSRange = (attString.string as NSString).rangeOfString(recipient, options: nil, range: NSMakeRange(position, attString.length-position))
cardHeader.addLinkToTransitInformation(recipientDictionary, withRange: rangeRecipient)
index = index + 1
if (index == 5) {
let recipientsDictionary:[String: AnyObject] = ["recipients": recipients]
let rangeRecipients : NSRange = (attString.string as NSString).rangeOfString("and \(recipients.count - index) other")
cardHeader.addLinkToTransitInformation(recipientsDictionary, withRange: rangeRecipients)
}
position = position + rangeRecipient.length
}
}
return cardHeader
}
}
extension EmailCellNode {
class FrameSet {
let cardHeaderFrame: CGRect
init(node: EmailCellNode, calculatedSize: CGSize) {
var calculatedcardHeaderFrame = CGRect(origin: CGPointMake(senderPhotoFrame.maxX + 8, senderPhotoFrame.minY) , size: node.cardHeaderNode.calculatedSize)
cardHeaderFrame = calculatedcardHeaderFrame.integerRect.integerRect
}
}
}
我不熟悉AsyncDisplayKit,但是你使用的时候有一些问题TTTAttributedLabel
:
您正在使用 TTTAttributedLabel()
初始化标签,它调用 init
。您必须改为使用指定的初始化程序 initWithFrame:
或 initWithCoder:
,因为 init
不会正确初始化 links
数组和各种其他内部属性。在 TTTAttributedLabel
的最新版本中,init
被标记为不可用。
您正在分配给 attributedText
属性。请在 TTTAttributedLabel.h
中查看此注释:
@bug Setting attributedText
directly is not recommended, as it may cause a crash when attempting to access any links previously set. Instead, call setText:
, passing an NSAttributedString
.
你永远不应该分配给 attributedText
属性.
我最终只使用了 ASTextNode
它没有 TTTAttributedLabel
那样多的功能,但足以满足我的需要。此外,由于它很重ASCollectionView
,所以最好完全异步。下面是我如何在 ASCellNode
中创建复合体 ASTextNode
.
的示例
这是最终结果,可点击名称通过 segue 传递 JSON 数据。
这里是构建 NSAttributedString
的简化版本
func createAttributedLabel(mailData: JSON) -> NSAttributedString{
var 收件人:[String] = []
for (key: String, subJson: JSON) in mailData["To"] {
if let recipientName = subJson["Name"].string {
recipients.append(recipientName)
}
}
// Add recipients to attributed string and save ranges for each
var index = 0
var position = senderName.length + 2
for recipient in recipients {
let recipientDictionary:[String: AnyObject] = ["recipient": recipient,"index": index ]
let recipientJSON = mailData["To"][index]
attString.appendAttributedString(NSAttributedString(string: ", \(recipient)"))
let rangeRecipient : NSRange = (attString.string as NSString).rangeOfString(recipient, options: nil, range: NSMakeRange(position, attString.length-position))
attString.addAttributes([
kLinkAttributeName: recipientJSON.rawValue,
NSForegroundColorAttributeName: UIColor.blackColor(),
NSFontAttributeName: UIFont(name: "SourceSansPro-Semibold", size: 14)!,
NSUnderlineStyleAttributeName: NSUnderlineStyle.StyleNone.rawValue],
range: rangeRecipient)
}
index = index + 1
return attString
}
然后结束以检测 link 轻敲。我必须转换原始值中的 JSON 才能传递数据。
func textNode(textNode: ASTextNode!, tappedLinkAttribute attribute: String!, value: AnyObject!, atPoint point: CGPoint, textRange: NSRange) {
// The node tapped a link; open it if it's a valid URL
if (value.isKindOfClass(NSDictionary)) {
var jsonTransferred = JSON(rawValue: value as! NSDictionary)
self.delegate.callSegueFromCellUser(data: jsonTransferred!)
} else {
var jsonTransferred = JSON(rawValue: value as! NSArray)
self.delegate.callSegueFromCellRecipients(data: jsonTransferred!)
}
}
我是 ASDK 的主要维护者之一,很乐意帮助您应对任何挑战 — 欢迎在项目上提出 GitHub 问题(即使只是提出问题)。
您喜欢 TTT 的 ASTextNode 缺少哪些功能?它确实处理链接,完成了多个、不相交和换行链接之间基于质心的点击消歧。可能缺少功能,但由于该项目被广泛使用,我敢打赌其他开发人员会发现添加任何您认为需要的功能很有用。
就是说,如果您不需要移动文本布局和从主线程渲染带来的显着性能提升,您可以将 TTT 包装在 initWithViewBlock 中 — 或者直接创建和添加视图,无需节点包装,在任何节点的 -didLoad 方法内。通常使用 ASDK,不需要包装视图(这就是我询问 ASTextNode 的原因)。
祝你工作顺利!
我已经构建了一个 ASCellNode
,它运行良好。但是,当我使用传统的 UICollectionViewCell
时,我使用了带链接的 TTTAttributedLabel
。
我不知道如何用 AsyncDisplayKit
我可以将 TTTAttributedLabel
中的 attriubtedText 分配给 ASTextNode
,但当然它不会保留链接。我怎么能有效地做到这一点。以我的 ASCellNode
.
protocol EmailSentDelegator : class {
func callSegueFromCell(data object: JSON)
}
class EmailCellNode: ASCellNode, TTTAttributedLabelDelegate {
let cardHeaderNode: ASTextNode
var frameSetOrNil: FrameSet?
init(mailData: JSON) {
// Create Nodes
cardHeaderNode = ASTextNode()
super.init()
// Set Up Nodes
cardHeaderNode.attributedString = createAttributedLabel(mailData, self).attributedText
// Build Hierarchy
addSubnode(cardHeaderNode)
}
override func calculateSizeThatFits(constrainedSize: CGSize) -> CGSize {
var cardSize = CGSizeZero
cardSize.width = UIScreen.mainScreen().bounds.size.width - 16
// Measure subnodes
let cardheaderSize = cardHeaderNode.measure(CGSizeMake(cardSize.width - 56, constrainedSize.height))
cardSize.height = max(cardheaderSize.height,40) + subjectLabelSize.height + timeStampSize.height + emailAbstractSize.height + 30
// Calculate frames
frameSetOrNil = FrameSet(node: self, calculatedSize: cardSize)
return cardSize
}
override func layout() {
if let frames = frameSetOrNil {
cardHeaderNode.frame = frames.cardHeaderFrame
}
}
func attributedLabel(label: TTTAttributedLabel!, didSelectLinkWithTransitInformation components: [NSObject : AnyObject]!) {
self.delegate.callSegueFromCell(data: mailData)
}
func createAttributedLabel(mailData: JSON, cell: EmailCellNode) -> TTTAttributedLabel{
let senderName = mailData["From"]["Name"].string!
var recipients:[String] = []
for (key: String, subJson: JSON) in mailData["To"] {
if let recipientName = subJson["Name"].string {
recipients.append(recipientName)
}
}
var cardHeader = TTTAttributedLabel()
cardHeader.setText("")
cardHeader.delegate = cell
cardHeader.userInteractionEnabled = true
// Add sender to attributed string and save range
var attString = NSMutableAttributedString(string: "\(senderName) to")
let senderDictionary:[String:String] = ["sender": senderName]
let rangeSender : NSRange = (attString.string as NSString).rangeOfString(senderName)
// Check if recipients is nil and add undisclosed recipients
if recipients.count == 0 {
attString.appendAttributedString(NSAttributedString(string: " undisclosed recipients"))
let rangeUndisclosed : NSRange = (attString.string as NSString).rangeOfString("undisclosed recipients")
attString.addAttribute(NSFontAttributeName, value: UIFont(name: "SourceSansPro-Semibold", size: 14)!, range: rangeUndisclosed)
attString.addAttribute(NSForegroundColorAttributeName, value: UIColor.grayColor(), range: rangeUndisclosed)
} else {
// Add recipients (first 5) to attributed string and save ranges for each
var index = 0
for recipient in recipients {
if (index == 0) {
attString.appendAttributedString(NSAttributedString(string: " \(recipient)"))
} else if (index == 5){
attString.appendAttributedString(NSAttributedString(string: ", and \(recipients.count - index) other"))
break
} else {
attString.appendAttributedString(NSAttributedString(string: ", \(recipient)"))
}
index = index + 1
}
}
cardHeader.attributedText = attString
// Adding recipients and sender links with recipient object to TTTAttributedLabel
cardHeader.addLinkToTransitInformation(senderDictionary, withRange: rangeSender)
if recipients.count != 0 {
var index = 0
var position = senderName.length + 2
for recipient in recipients {
let recipientDictionary:[String: AnyObject] = ["recipient": recipient,"index": index ]
let rangeRecipient : NSRange = (attString.string as NSString).rangeOfString(recipient, options: nil, range: NSMakeRange(position, attString.length-position))
cardHeader.addLinkToTransitInformation(recipientDictionary, withRange: rangeRecipient)
index = index + 1
if (index == 5) {
let recipientsDictionary:[String: AnyObject] = ["recipients": recipients]
let rangeRecipients : NSRange = (attString.string as NSString).rangeOfString("and \(recipients.count - index) other")
cardHeader.addLinkToTransitInformation(recipientsDictionary, withRange: rangeRecipients)
}
position = position + rangeRecipient.length
}
}
return cardHeader
}
}
extension EmailCellNode {
class FrameSet {
let cardHeaderFrame: CGRect
init(node: EmailCellNode, calculatedSize: CGSize) {
var calculatedcardHeaderFrame = CGRect(origin: CGPointMake(senderPhotoFrame.maxX + 8, senderPhotoFrame.minY) , size: node.cardHeaderNode.calculatedSize)
cardHeaderFrame = calculatedcardHeaderFrame.integerRect.integerRect
}
}
}
我不熟悉AsyncDisplayKit,但是你使用的时候有一些问题TTTAttributedLabel
:
您正在使用
TTTAttributedLabel()
初始化标签,它调用init
。您必须改为使用指定的初始化程序initWithFrame:
或initWithCoder:
,因为init
不会正确初始化links
数组和各种其他内部属性。在TTTAttributedLabel
的最新版本中,init
被标记为不可用。您正在分配给
attributedText
属性。请在TTTAttributedLabel.h
中查看此注释:@bug Setting
attributedText
directly is not recommended, as it may cause a crash when attempting to access any links previously set. Instead, callsetText:
, passing anNSAttributedString
.你永远不应该分配给
attributedText
属性.
我最终只使用了 ASTextNode
它没有 TTTAttributedLabel
那样多的功能,但足以满足我的需要。此外,由于它很重ASCollectionView
,所以最好完全异步。下面是我如何在 ASCellNode
中创建复合体 ASTextNode
.
这是最终结果,可点击名称通过 segue 传递 JSON 数据。
这里是构建 NSAttributedString
func createAttributedLabel(mailData: JSON) -> NSAttributedString{ var 收件人:[String] = []
for (key: String, subJson: JSON) in mailData["To"] {
if let recipientName = subJson["Name"].string {
recipients.append(recipientName)
}
}
// Add recipients to attributed string and save ranges for each
var index = 0
var position = senderName.length + 2
for recipient in recipients {
let recipientDictionary:[String: AnyObject] = ["recipient": recipient,"index": index ]
let recipientJSON = mailData["To"][index]
attString.appendAttributedString(NSAttributedString(string: ", \(recipient)"))
let rangeRecipient : NSRange = (attString.string as NSString).rangeOfString(recipient, options: nil, range: NSMakeRange(position, attString.length-position))
attString.addAttributes([
kLinkAttributeName: recipientJSON.rawValue,
NSForegroundColorAttributeName: UIColor.blackColor(),
NSFontAttributeName: UIFont(name: "SourceSansPro-Semibold", size: 14)!,
NSUnderlineStyleAttributeName: NSUnderlineStyle.StyleNone.rawValue],
range: rangeRecipient)
}
index = index + 1
return attString
}
然后结束以检测 link 轻敲。我必须转换原始值中的 JSON 才能传递数据。
func textNode(textNode: ASTextNode!, tappedLinkAttribute attribute: String!, value: AnyObject!, atPoint point: CGPoint, textRange: NSRange) {
// The node tapped a link; open it if it's a valid URL
if (value.isKindOfClass(NSDictionary)) {
var jsonTransferred = JSON(rawValue: value as! NSDictionary)
self.delegate.callSegueFromCellUser(data: jsonTransferred!)
} else {
var jsonTransferred = JSON(rawValue: value as! NSArray)
self.delegate.callSegueFromCellRecipients(data: jsonTransferred!)
}
}
我是 ASDK 的主要维护者之一,很乐意帮助您应对任何挑战 — 欢迎在项目上提出 GitHub 问题(即使只是提出问题)。
您喜欢 TTT 的 ASTextNode 缺少哪些功能?它确实处理链接,完成了多个、不相交和换行链接之间基于质心的点击消歧。可能缺少功能,但由于该项目被广泛使用,我敢打赌其他开发人员会发现添加任何您认为需要的功能很有用。
就是说,如果您不需要移动文本布局和从主线程渲染带来的显着性能提升,您可以将 TTT 包装在 initWithViewBlock 中 — 或者直接创建和添加视图,无需节点包装,在任何节点的 -didLoad 方法内。通常使用 ASDK,不需要包装视图(这就是我询问 ASTextNode 的原因)。
祝你工作顺利!