【问题标题】:Get line break in UILabel due to Autolayout由于自动布局,在 UILabel 中获取换行符
【发布时间】:2017-11-09 16:46:19
【问题描述】:

当 UILabel 在手机屏幕上使用自动布局显示时,我想获取带有换行符的文本。谢谢。

例如:如果我分配

label.text = "dhasghdsgah dgahjdg ahjgd hkagkhdhk ajsh djkah"

当它显示在屏幕上时,根据屏幕宽度显示如下:

dhasghdsgah dgahjdg ahjgd

 hkagkhdhk ajsh

  djkah

我想知道 '\n' 被自动布局插入到了哪里。

如果我遗漏了什么,请纠正我。

请查看截图: 标签中没有空格。

【问题讨论】:

  • 你到底想要什么?
  • 它进入下一行,因为UILabel 无法在可用空间中容纳整个单词。例如 djkah 根据 xcode 将不适合第二行。
  • 我想获取 UI 上显示的带有换行符的文本
  • 你想达到什么目的?
  • 我必须将文本发送到服务器,其中包含基于 UI 上显示的标签的行更改等详细信息。 @狮子

标签: ios autolayout uilabel line-breaks


【解决方案1】:

这是用于检测 UILabel 中的换行符的代码

- (int)getLengthForString:(NSString *)str fromFrame:(CGRect)frame withFont:(UIFont *)font
{
    int length = 1;
    int lastSpace = 1;
    NSString *cutText = [str substringToIndex:length];
    CGSize textSize = [cutText sizeWithFont:font constrainedToSize:CGSizeMake(frame.size.width, frame.size.height + 500)];
    while (textSize.height <= frame.size.height)
    {
        NSRange range = NSMakeRange (length, 1);
        if ([[str substringWithRange:range] isEqualToString:@" "])
        {
            lastSpace = length;
        }
        length++;
        cutText = [str substringToIndex:length];
        textSize = [cutText sizeWithFont:font constrainedToSize:CGSizeMake(frame.size.width, frame.size.height + 500)];
    }
    return lastSpace;
}


-(NSString*) getLinebreaksWithString:(NSString*)labelText forWidth:(CGFloat)lblWidth forPoint:(CGPoint)point
{
    //Create Label
    UILabel *label = [[UILabel alloc] init];
    label.text = labelText;
    label.numberOfLines = 0;
    label.lineBreakMode = NSLineBreakByWordWrapping;

    //Set frame according to string
    CGSize size = [label.text sizeWithFont:label.font
                         constrainedToSize:CGSizeMake(lblWidth, MAXFLOAT)
                             lineBreakMode:UILineBreakModeWordWrap];
    [label setFrame:CGRectMake(point.x , point.y , size.width , size.height)];

    //Add Label in current view
    [self.view addSubview:label];

    //Count the total number of lines for the Label which has NSLineBreakByWordWrapping line break mode
    int numLines = (int)(label.frame.size.height/label.font.leading);

    //Getting and dumping lines from text set on the Label
    NSMutableArray *allLines = [[NSMutableArray alloc] init];

    BOOL shouldLoop = YES;
    while (shouldLoop)
    {
        //Getting length of the string from rect with font
        int length = [self getLengthForString:labelText fromFrame:CGRectMake(point.x, point.y, size.width, size.height/numLines) withFont:label.font] + 1;        

        [allLines addObject:[labelText substringToIndex:length]];

        labelText = [labelText substringFromIndex:length];
        if(labelText.length<length)
            shouldLoop = NO;
    }

    [allLines addObject:labelText];
    //NSLog(@"\n\n%@\n",allLines);

    return [allLines componentsJoinedByString:@"\n"];
}

如何使用:

NSString *labelText = @"We are what our thoughts have made us; so take care about what you think. Words are secondary. Thoughts live; they travel far.";

NSString *stringWithLineBreakChar = [self getLinebreaksWithString:labelText forWidth:200 forPoint:CGPointMake(15, 15)];
NSLog(@"\n\n%@",stringWithLineBreakChar);

您只需要设置 getLinebreaksWithString 所需的参数,您将获得一个包含每个“\n”中断的字符串。 使用您在情节提要中设计的标签宽度和起点。

参考:https://stackoverflow.com/a/15243686/6904341

【讨论】:

  • 是的,我知道。但是我需要在 UI 上显示的带有换行符的确切文本,以便我可以将其发送到服务器并复制相同的内容。
  • @Antik Ku​​mar Gupta 你可以看到stackoverflow.com/a/15243686/6904341
  • 你能帮我一个快速的版本吗?
  • 我用 Swift 编写了上面的内容,但这会在 2 个字符后截断并在此处放置一个 '\n'。请纠正我的错误。
  • 你没有提到特定的语言,我已经给你答案了。我没有迅速尝试。我想你可以接受我的回答。
【解决方案2】:

我用这个方法解决了这个问题:

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

    let text:NSString = label.text! as NSString
    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: CGFloat(0), y: CGFloat(0), width: CGFloat(rect.size.width), height: CGFloat(100000)), transform: .identity)

    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
}

此方法返回不同行的字符串数组。现在您可以根据需要使用此数组创建一个带有 \n 连接的新字符串。

我的用法:

            var stringArray = [String]()

            for newItem in self.getLinesArrayOfStringInLabel(label: item.labelToAdd) {
                stringArray.append(newItem.replacingOccurrences(of: "\n", with: ""))
            }
            let stringToSend = stringArray.joined(separator: "\n")
            print(stringToSend)

请随时询问任何细节。谢谢

【讨论】:

  • 所以你在没有我帮助的情况下解决了:D,这就是为什么 10+5 分给你。
  • 大声笑,谢谢先生:)
【解决方案3】:

这是为 UILabel 添加背景的代码,但它通过查看文本宽度超过标签宽度的点来检测换行符。

-(CAShapeLayer *)backgroundLayerForLabel:(UILabel *)label padding:(float)padding{

    NSString * text = label.text;
    NSArray * words = [text componentsSeparatedByString:@" "];

    UILabel * sizeLabel = [UILabel new];
    sizeLabel.frame = CGRectMake(0, 0, label.frame.size.width, 0);
    sizeLabel.font = label.font;
    [sizeLabel setText:@" "]; //just to get row height

    float rowHeight = sizeLabel.intrinsicContentSize.height;
    float runWidth = 0.0f;
    float maxWidth = ceilf(label.frame.size.width);

    float startingX = label.frame.origin.x - padding;
    UIBezierPath * path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(startingX, label.frame.origin.y)];

    for (NSString * word in words){

        [sizeLabel setText:[NSString stringWithFormat:@"%@", word]];
        float sizeWidth = sizeLabel.intrinsicContentSize.width;

        [sizeLabel setText:[NSString stringWithFormat:@"%@ ", word]];
        float sizeSpaceWidth = sizeLabel.intrinsicContentSize.width;

        float nextWidth = floorf(sizeWidth + runWidth);
        if (nextWidth > maxWidth){ //spans next line

            [path addLineToPoint:CGPointMake(startingX + runWidth + padding, path.currentPoint.y)];
            [path addLineToPoint:CGPointMake(path.currentPoint.x, path.currentPoint.y + rowHeight)];

            runWidth = sizeSpaceWidth;

        } else {

            runWidth += sizeSpaceWidth;
        }

    }
    [path addLineToPoint:CGPointMake(startingX + runWidth + padding, path.currentPoint.y)];
    [path addLineToPoint:CGPointMake(path.currentPoint.x, path.currentPoint.y + rowHeight)];
    [path addLineToPoint:CGPointMake(startingX, path.currentPoint.y)];
    [path closePath];

    CAShapeLayer * layer = [CAShapeLayer layer];
    layer.path = path.CGPath;
    layer.fillColor = [UIColor whiteColor].CGColor;
    return layer;

}

nextWidth > maxWidth,这就是你的换行符开始的地方,runWidth 变量是句子的长度。像这样使用:

    UILabel * label = [UILabel new];
    label.frame = CGRectMake(20, localY, labelWidth, 0);
    label.font = [UIFont systemFontOfSize:24.0f weight:UIFontWeightSemibold];
    label.textColor = [UIColor blackColor];
    label.text = @"This is a really long quotes. I know. a. b. c. defghi. jklmn. op. q. r. stuv. ";
    label.numberOfLines = 4;
    label.lineBreakMode = NSLineBreakByWordWrapping;
    [label sizeToFit];

    CAShapeLayer * layer = [self backgroundLayerForLabel:label padding:5.0f];
    layer.shadowColor = [UIColor blackColor].CGColor;
    layer.shadowOffset = CGSizeMake(0, 1);
    layer.shadowRadius = 2.0f;
    layer.shadowOpacity = 0.8f;
    [cell.layer addSublayer:layer];
    [cell addSubview:label];

给你这样的东西:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-29
    • 1970-01-01
    • 2016-03-15
    相关资源
    最近更新 更多