2016-03-16 99 views
2

我有一個問題,「boundingRectForGlyphRange」總是返回CGRect.zero「0.0,0.0,0.0,0.0」。 「boundingRectForGlyphRange」不起作用。例如,我正在編寫觸摸UILabel功能部分文本的代碼。我的文本的第一部分是「任何文本」,第二部分是「閱讀更多」。當我觸摸「閱讀更多」時,我只需要輕觸識別器就可以工作。如果我用手觸摸的UILabel的任何一點,「CGRectContainsPoint」總是返回true,那麼行動稱爲Swift:點擊UILabel文本的一部分

這裏我的代碼:

override func viewDidLoad() { 
     super.viewDidLoad() 

     // The full string 

     let firstPart:NSMutableAttributedString = NSMutableAttributedString(string: "Lorem ipsum dolor set amit ", attributes: [NSFontAttributeName: UIFont.systemFontOfSize(13)]) 
     firstPart.addAttribute(NSForegroundColorAttributeName, value: UIColor.blackColor(), 
      range: NSRange(location: 0, length: firstPart.length)) 
     info.appendAttributedString(firstPart) 

     // The "Read More" string that should be touchable 
     let secondPart:NSMutableAttributedString = NSMutableAttributedString(string: "READ MORE", attributes: [NSFontAttributeName: UIFont.systemFontOfSize(14)]) 
     secondPart.addAttribute(NSForegroundColorAttributeName, value: UIColor.blackColor(), 
      range: NSRange(location: 0, length: secondPart.length)) 
     info.appendAttributedString(secondPart) 

     lblTest.attributedText = info 

     // Store range of chars we want to detect touches for 
     moreStringRange = NSMakeRange(firstPart.length, secondPart.length) 
     print("moreStringRange\(moreStringRange)") 

     tapRec.addTarget(self, action: "didTap:") 
     lblTest.addGestureRecognizer(tapRec) 

    } 


    func didTap(sender:AnyObject) { 
     // Storage class stores the string, obviously 
     let textStorage:NSTextStorage = NSTextStorage(attributedString: info) 
     // The storage class owns a layout manager 
     let layoutManager:NSLayoutManager = NSLayoutManager() 
     textStorage.addLayoutManager(layoutManager) 

     // Layout manager owns a container which basically 
     // defines the bounds the text should be contained in 
     let textContainer:NSTextContainer = NSTextContainer(size: lblTest.frame.size) 
     textContainer.lineFragmentPadding = 0 
     textContainer.lineBreakMode = lblTest.lineBreakMode 

     // Begin computation of actual frame 
     // Glyph is the final display representation 
     var glyphRange = NSRange() 
     // Extract the glyph range 
     layoutManager.characterRangeForGlyphRange(moreStringRange!, actualGlyphRange: &glyphRange) 

     // Compute the rect of glyph in the text container 
     print("glyphRange\(glyphRange)") 
     print("textContainer\(textContainer)") 
     let glyphRect:CGRect = layoutManager.boundingRectForGlyphRange(glyphRange, inTextContainer: textContainer) 

     // Final rect relative to the textLabel. 
     print("\(glyphRect)") 

     // Now figure out if the touch point is inside our rect 
     let touchPoint:CGPoint = tapRec.locationOfTouch(0, inView: lblTest) 

     if CGRectContainsPoint(glyphRect, touchPoint) { 
      print("User tapped on Read More. So show something more") 
     } 
    } 

它只是爲了測試我想要做一個演示:

enter image description here

任何幫助將不勝感激。

+0

希望這會幫助你[閱讀更多](http:// stackoverflow。com/questions/32309247/add-read-up-of-the-end-of-uilabel) – iMuzahid

+0

如何使用兩個標籤? – Koen

+0

@Koen:這只是一個演示。我的文字有許多附件。我不能使用很多標籤。 – Ashley

回答

3

您的文本工具包堆棧有問題。您忘了將文本容器添加到佈局管理器!因此沒有文字佈局,並且佈局管理器無法報告任何字形矩形。因此,該字形rect是NSRectZero,這就是爲什麼你永遠不能報告其中的一個水龍頭。

另一個問題是,你打電話給characterRangeForGlyphRange當你應該打電話glyphRangeForCharacterRange,你似乎不知道如何使用結果(實際上,你扔掉結果)。

這是工作代碼,只顯示有關使用文本堆棧的部分。我從字符串「Hello to you」開始。我將展示如何學習,其中矩形的「來」是:

let s = "Hello to you" 
let ts = NSTextStorage(
    attributedString: NSAttributedString(string:s)) 
let lm = NSLayoutManager() 
ts.addLayoutManager(lm) 
let tc = NSTextContainer(size: CGSizeMake(4000,400)) 
lm.addTextContainer(tc) // **** 
tc.lineFragmentPadding = 0 
let toRange = (s as NSString).rangeOfString("to") 
let gr = lm.glyphRangeForCharacterRange(
    toRange, actualCharacterRange: nil) // **** 
let glyphRect = lm.boundingRectForGlyphRange(
    gr, inTextContainer: tc) 

結果是{x 30.68 y 0 w 10.008 h 13.8}。現在我們可以繼續測試一下水龍頭是否在那個位置。去吧,去做吧。

+0

感謝您的幫助,我很抱歉我的不好的知識。我正在努力加強它。 – Ashley

4

斯威夫特3.我已經開發了一個擴展:

extension UILabel { 
     ///Find the index of character (in the attributedText) at point 
     func indexOfAttributedTextCharacterAtPoint(point: CGPoint) -> Int { 
      assert(self.attributedText != nil, "This method is developed for attributed string") 
      let textStorage = NSTextStorage(attributedString: self.attributedText!) 
      let layoutManager = NSLayoutManager() 
      textStorage.addLayoutManager(layoutManager) 
      let textContainer = NSTextContainer(size: self.frame.size) 
      textContainer.lineFragmentPadding = 0 
      textContainer.maximumNumberOfLines = self.numberOfLines 
      textContainer.lineBreakMode = self.lineBreakMode 
      layoutManager.addTextContainer(textContainer) 

      let index = layoutManager.characterIndex(for: point, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil) 
      return index 
     } 
    } 

現在我可以檢查是否竊聽字符是範圍:

 let range = SOME_RANGE 
     let tapLocation = gesture.location(in: MY_TEXT_LABEL) 
     let index = textLbl.indexOfAttributedTextCharacterAtPoint(point: tapLocation) 

     if index > range.location && index < range.location + range.length { 
     //YES, THE TAPPED CHARACTER IS IN RANGE 
     } 
+0

謝謝。這真的很有幫助。在多行文本中,當我們實現這個擴展時,底線不會被點擊。此外,我們嘗試'讓textContainer = NSTextContainer(size:CGSize(width:(self.label?.frame.width)!, height:(self.label.frame.height)+100))'但沒有機會。 –

+0

好方法。但它不涉及非左對齊的文本(例如中心或右邊)。看起來像沒有辦法從'UILabel'傳遞對齊到'NSTextContainer' – brigadir

4

具有這種東西的幾個問題後, ,使用很多不同的館藏等...我發現了一個有趣的解決方案:我發現了一個有趣的解決方案: http://samwize.com/2016/03/04/how-to-create-multiple-tappable-links-in-a-uilabel/

它即將擴展UITapGestureRegonizer並檢測是否當觸發時,水龍頭位於字符串的範圍內。

這裏是更新斯威夫特4版本的擴展:

extension UITapGestureRecognizer { 

    func didTapAttributedTextInLabel(label: UILabel, inRange targetRange: NSRange) -> Bool { 
     // Create instances of NSLayoutManager, NSTextContainer and NSTextStorage 
     let layoutManager = NSLayoutManager() 
     let textContainer = NSTextContainer(size: CGSize.zero) 
     let textStorage = NSTextStorage(attributedString: label.attributedText!) 

     // Configure layoutManager and textStorage 
     layoutManager.addTextContainer(textContainer) 
     textStorage.addLayoutManager(layoutManager) 

     // Configure textContainer 
     textContainer.lineFragmentPadding = 0.0 
     textContainer.lineBreakMode = label.lineBreakMode 
     textContainer.maximumNumberOfLines = label.numberOfLines 
     let labelSize = label.bounds.size 
     textContainer.size = labelSize 

     // Find the tapped character location and compare it to the specified range 
     let locationOfTouchInLabel = self.location(in: label) 
     let textBoundingBox = layoutManager.usedRect(for: textContainer) 

     let textContainerOffset = CGPoint(x: (labelSize.width - textBoundingBox.size.width) * 0.5 - textBoundingBox.origin.x, y: (labelSize.height - textBoundingBox.size.height) * 0.5 - textBoundingBox.origin.y) 

     let locationOfTouchInTextContainer = CGPoint(x: locationOfTouchInLabel.x - textContainerOffset.x, y: locationOfTouchInLabel.y - textContainerOffset.y) 
     let indexOfCharacter = layoutManager.characterIndex(for: locationOfTouchInTextContainer, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil) 
     return NSLocationInRange(indexOfCharacter, targetRange) 
    } 

} 

爲了簡化量程轉換,還需要這個範圍擴展

extension Range where Bound == String.Index { 
    var nsRange:NSRange { 
     return NSRange(location: self.lowerBound.encodedOffset, 
        length: self.upperBound.encodedOffset - 
        self.lowerBound.encodedOffset) 
    } 
} 

一旦你有了這個擴展,你可以添加輕點手勢到您的標籤:

let tap = UITapGestureRecognizer(target: self, action: #selector(tapLabel(tap:))) 
self.yourLabel.addGestureRecognizer(tap) 
self.yourLabel.isUserInteractionEnabled = true 

以下是處理水龍頭的功能:

@objc func tapLabel(tap: UITapGestureRecognizer) { 
    guard let range = self.yourLabel.text?.range(of: "Substring to detect")?.nsRange else { 
     return 
    } 
    if tap.didTapAttributedTextInLabel(label: self.yourLabel, inRange: range) { 
     // Substring tapped 
    } 
} 
+0

這對我的解決方案非常有幫助。謝謝! –