2010-12-12 49 views
12

有沒有簡單的方法來獲取(或簡單地顯示)來自UILabel中給定行的文本?如何從UILabel的第n行獲取文本?

我的UILabel正確顯示我的文本,並將其鋪設得很漂亮,但偶爾我需要能夠顯示某些行,但顯然我需要知道UILabel如何定位所有內容來執行此操作。

我知道這可以很容易地完成一個子字符串,但我需要知道該行的開始和結束點。

或者我可以滾動UILabel,如果有某種偏移到UILabel的框架並隱藏我不想看到的內容的其餘部分。

我一直無法發現任何可以輕鬆完成這項工作的東西。任何人有任何好主意?

感謝

iphaaw

回答

4

我不認爲有這樣做的(像 「takethenline」 法)原生方式。
我可以找出一個棘手的解決方案,但我不知道是最好的解決方案。
你可以將你的標籤分成一個單詞的數組。
那麼你可以循環數組和檢查文本高度,直到像這樣的字:

NSString *texttocheck; 
float old_height = 0; 
int linenumber = 0; 

for (x=0; x<[wordarray lenght]; x++) { 
    texttocheck = [NSString stringWithFormat:@"%@ %@", texttocheck, [wordarray objectAtIndex:x]]; 

    float height = [text sizeWithFont:textLabel.font 
        constrainedToSize:CGSizeMake(textLabel.bounds.size.width,99999) 
         lineBreakMode:UILineBreakModeWordWrap].height; 

    if (old_height < height) { 
     linenumber++; 
    } 
} 

如果高度的變化,這意味着有字之前換行。
我無法檢查語法是否現在寫入正確,因此您必須自己檢查它。

0

如果您的所有角色都以相同的尺寸顯示,即它們被包含在一個通用尺寸的框中,您可以利用它。 (例如,對於日文字符,這似乎就是這種情況。)

否則,您可以查詢顯示字體中每個字符的大小並計算該行必須是什麼。

唯一的擔憂是你的計算可能不同意蘋果在幕後做的事 - 在這種情況下,我建議你去重寫文本框架圖的麻煩。在文檔中查找核心文本。

(也可能是我這樣做不對,但我沒有發現蘋果的一種方法,在文檔給出很準確,所以我沒有別的東西我自己。)

19

我有更好的方式來發現。

你可以在CoreText.framework的幫助下得到這個。

1.添加CoreText.framework
2.進口#import <CoreText/CoreText.h>
然後使用下面的方法:

- (NSArray *)getLinesArrayOfStringInLabel:(UILabel *)label { 
    NSString *text = [label text]; 
    UIFont *font = [label font]; 
    CGRect rect = [label frame]; 

    CTFontRef myFont = CTFontCreateWithName((__bridge CFStringRef)([font fontName]), [font pointSize], NULL); 
    NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:text]; 
    [attStr addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)myFont range:NSMakeRange(0, attStr.length)]; 


    CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attStr); 

    CGMutablePathRef path = CGPathCreateMutable(); 
    CGPathAddRect(path, NULL, CGRectMake(0,0,rect.size.width,100000)); 

    CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL); 

    NSArray *lines = (__bridge NSArray *)CTFrameGetLines(frame); 
    NSMutableArray *linesArray = [[NSMutableArray alloc]init]; 

    for (id line in lines) 
    { 
     CTLineRef lineRef = (__bridge CTLineRef)line; 
     CFRange lineRange = CTLineGetStringRange(lineRef); 
     NSRange range = NSMakeRange(lineRange.location, lineRange.length); 

     NSString *lineString = [text substringWithRange:range]; 
     [linesArray addObject:lineString]; 
    } 

    return (NSArray *)linesArray; 
} 

調用此方法: -

NSArray *linesArray = [self getLinesArrayOfStringInLabel:yourLabel]; 

現在你可以使用linesArray

+0

真棒答案....擡起頭....保存了很多我的時間。謝謝.. – 2015-08-26 11:29:55

+0

很棒,很棒。非常感謝。 – 2016-04-18 15:00:57

5

回答與適當的釋放!!!!

-(NSArray *)getLinesArrayOfStringInLabel:(UILabel *)label 
{ 
    NSString *text = [label text]; 
    UIFont *font = [label font]; 
    CGRect rect = [label frame]; 

    CTFontRef myFont = CTFontCreateWithName((CFStringRef)([font fontName]), [font pointSize], NULL); 
    NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:text]; 
    [attStr addAttribute:(NSString *)kCTFontAttributeName value:(id)myFont range:NSMakeRange(0, attStr.length)]; 

    CFRelease(myFont); 

    CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attStr); 

    CGMutablePathRef path = CGPathCreateMutable(); 
    CGPathAddRect(path, NULL, CGRectMake(0,0,rect.size.width,100000)); 

    CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL); 

    NSArray *lines = (NSArray *)CTFrameGetLines(frame); 

    NSMutableArray *linesArray = [[NSMutableArray alloc]init]; 

    for (id line in lines) 
    { 
     CTLineRef lineRef = (CTLineRef)line; 
     CFRange lineRange = CTLineGetStringRange(lineRef); 
     NSRange range = NSMakeRange(lineRange.location, lineRange.length); 

     NSString *lineString = [text substringWithRange:range]; 

     CFAttributedStringSetAttribute((CFMutableAttributedStringRef)attStr, lineRange, kCTKernAttributeName, (CFTypeRef)([NSNumber numberWithFloat:0.0])); 
     CFAttributedStringSetAttribute((CFMutableAttributedStringRef)attStr, lineRange, kCTKernAttributeName, (CFTypeRef)([NSNumber numberWithInt:0.0])); 

     //NSLog(@"''''''''''''''''''%@",lineString); 
     [linesArray addObject:lineString]; 

    } 
    [attStr release]; 

    CGPathRelease(path); 
    CFRelease(frame); 
    CFRelease(frameSetter); 


    return (NSArray *)linesArray; 
} 
7

夫特3

func getLinesArrayFromLabel(label:UILabel) -> [String] { 

     let text:NSString = label.text! as NSString // TODO: Make safe? 
     let font:UIFont = label.font 
     let rect:CGRect = label.frame 

     let myFont:CTFont = CTFontCreateWithName(font.fontName as CFString, font.pointSize, nil) 
     let attStr:NSMutableAttributedString = NSMutableAttributedString(string: text as String) 
     attStr.addAttribute(String(kCTFontAttributeName), value:myFont, range: NSMakeRange(0, attStr.length)) 
     let frameSetter:CTFramesetter = CTFramesetterCreateWithAttributedString(attStr as CFAttributedString) 
     let path:CGMutablePath = CGMutablePath() 
     path.addRect(CGRect(x:0, y:0, width:rect.size.width, height:100000)) 

     let frame:CTFrame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, nil) 
     let lines = CTFrameGetLines(frame) as NSArray 
     var linesArray = [String]() 

     for line in lines { 
      let lineRange = CTLineGetStringRange(line as! CTLine) 
      let range:NSRange = NSMakeRange(lineRange.location, lineRange.length) 
      let lineString = text.substring(with: range) 
      linesArray.append(lineString as String) 
     } 
     return linesArray 
} 

夫特2(Xcode的7)的版本(測試,並從夫特1答案重新編輯)

func getLinesArrayOfStringInLabel(label:UILabel) -> [String] { 

let text:NSString = label.text! // TODO: Make safe? 
let font:UIFont = label.font 
let rect:CGRect = label.frame 

let myFont:CTFontRef = CTFontCreateWithName(font.fontName, font.pointSize, nil) 
let attStr:NSMutableAttributedString = NSMutableAttributedString(string: text as String) 
attStr.addAttribute(String(kCTFontAttributeName), value:myFont, range: NSMakeRange(0, attStr.length)) 
let frameSetter:CTFramesetterRef = CTFramesetterCreateWithAttributedString(attStr as CFAttributedStringRef) 
let path:CGMutablePathRef = CGPathCreateMutable() 
CGPathAddRect(path, nil, CGRectMake(0, 0, rect.size.width, 100000)) 
let frame:CTFrameRef = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, nil) 
let lines = CTFrameGetLines(frame) as NSArray 
var linesArray = [String]() 

for line in lines { 
    let lineRange = CTLineGetStringRange(line as! CTLine) 
    let range:NSRange = NSMakeRange(lineRange.location, lineRange.length) 
    let lineString = text.substringWithRange(range) 
    linesArray.append(lineString as String) 
} 
return linesArray 
} 
+1

此時應更換如下代碼 **讓文本:的NSString = label.text! // TODO:確保安全嗎?** 與 **保護讓文本:NSString = self.text else { return [] } ** – 2015-10-14 14:19:06

+4

起初它不適用於我 - 計算的行數是超過實際數量。但後來我將CGPathAddRect改爲:CGPathAddRect(path,nil,CGRectMake(0,0,rect.size.width + 15,100000)) ,它的工作方式與它應有的一樣。 – locomotion 2016-07-22 11:04:12

+0

這是不可靠的。見:https://stackoverflow.com/questions/46923039/get-each-line-of-text-in-a-uilabel – chicobermuda 2017-10-25 02:50:26

1

夫特3 - 的Xcode 8.1

我已經把從以前的代碼nswers創建夫特3時,Xcode 8.1兼容extensionUILabel返回標籤的第一行。

import CoreText 

extension UILabel { 

    /// Returns the String displayed in the first line of the UILabel or "" if text or font is missing 
    var firstLineString: String { 

    guard let text = self.text else { return "" } 
    guard let font = self.font else { return "" } 
    let rect = self.frame 

    let attStr = NSMutableAttributedString(string: text) 
    attStr.addAttribute(String(kCTFontAttributeName), value: CTFontCreateWithName(font.fontName as CFString, font.pointSize, nil), range: NSMakeRange(0, attStr.length)) 

    let frameSetter = CTFramesetterCreateWithAttributedString(attStr as CFAttributedString) 
    let path = CGMutablePath() 
    path.addRect(CGRect(x: 0, y: 0, width: rect.size.width + 7, height: 100)) 
    let frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, nil) 

    guard let line = (CTFrameGetLines(frame) as! [CTLine]).first else { return "" } 
    let lineString = text[text.startIndex...text.index(text.startIndex, offsetBy: CTLineGetStringRange(line).length-2)] 

    return lineString 
    } 
} 

要使用它,在你的UILabel例如簡單的通話firstLineString這樣的:

let firstLine = myLabel.firstLineString 
2

這是斯威夫特3版本讓所有的線路中的標籤。 (@fredpi有類似的答案,但它只適用於第一行)

extension UILabel { 

    func getArrayOfLinesInLabel() -> [String] { 

     let text = NSString(string: self.text ?? "-- -- -- --") 
     let font = self.font ?? // Your default font here 
     let rect = self.frame 

     let myFont = CTFontCreateWithName(font.fontName as CFString?, font.pointSize, nil) 
     let attStr = NSMutableAttributedString(string: text as String) 
     attStr.addAttribute(String(kCTFontAttributeName), value:myFont, range: NSRange(location: 0, length: attStr.length)) 
     let frameSetter = CTFramesetterCreateWithAttributedString(attStr as CFAttributedString) 
     let path = CGPath(rect: CGRect(x: 0, y: 0, width: rect.size.width, height: rect.size.height), transform: nil) 
     let frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, nil) 
     guard let lines = CTFrameGetLines(frame) as? [CTLine] else { 
      return [] 
     } 

     var linesArray = [String]() 

     for line in lines { 
      let lineRange = CTLineGetStringRange(line) 
      let range = NSRange(location: lineRange.location, length: lineRange.length) 
      let lineString = text.substring(with: range) 
      linesArray.append(lineString as String) 
     } 

     return linesArray 
    } 
}