如何将ASTextNode与TTTAttributedLabel一起使用

时间:2015-06-16 11:24:24

标签: swift uicollectionviewcell nsattributedstring tttattributedlabel asyncdisplaykit

我已经构建了一个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
        }
    }
}

3 个答案:

答案 0 :(得分:0)

我不熟悉AsyncDisplayKit,但使用TTTAttributedLabel时存在一些问题:

  • 您正在使用TTTAttributedLabel()初始化标签,该init会调用initWithFrame:。您必须使用指定的初始值设定项initWithCoder:init,因为links无法正确初始化TTTAttributedLabel数组和各种其他内部属性。在init的最新版本中,attributedText被标记为不可用。

  • 您正在分配TTTAttributedLabel.h属性。请参阅attributedText中的此说明:

      

    @bug不建议直接设置setText:,因为在尝试访问之前设置的任何链接时可能会导致崩溃。相反,请致电NSAttributedString,传递attributedText

    您永远不应该分配到0.6225E+0 0.2679E+03 0.0000E+00 0.0000E+00 -0.0000E+00 0.0000E+00 属性。

答案 1 :(得分:0)

我最终只使用ASTextNode它在TTTAttributedLabel没有那么多功能但足以满足我的需要。更进一步,因为它是一个沉重的ASCollectionView,最好完全去异步。在ASCellNode创建复杂ASTextNode的情况下,我就这样做了一个例子。

这是最终结果,可点击名称通过segue传递JSON数据。

enter image description here

这是构建NSAttributedString

的简化版本

func createAttributedLabel(mailData:JSON) - > NSAttributedString {     var recipients:[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

}

然后结束检测链接点击。我不得不在原始值中转换我的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!)
    }
}

答案 2 :(得分:0)

我是ASDK的主要维护者之一,并且愿意帮助您解决任何挑战 - 随意在项目上打开GitHub问题(即使只是为了提问)。

ASTextNode缺少哪些功能,您喜欢TTT?它确实处理链接,完成基于质心的多重,不相交和无关的消除歧义。换行链接。可能缺少功能,但由于项目使用得非常广泛,我敢打赌其他开发人员会发现添加任何你需要的功能都很有用。

也就是说,如果您不需要移动文本布局和渲染主线程所带来的显着性能提升,您可以将TTT包装在initWithViewBlock中 - 或者只是创建&在没有节点包装的情况下直接添加视图,在任何节点的-didLoad方法中。通常使用ASDK,不需要包装视图(这就是我询问ASTextNode的原因)。

祝你工作顺利!