6

我有一个带有图像的属性字符串(NSTextAttachment)。这没问题,但是我遇到了一个似乎无法解决的截断问题。

在示例中,假设字符串##是图像。所以我的字符串看起来像Hello world! ##. 在段落样式上设置尾部截断。

现在,如果空间受到限制,文本将被省略号截断(这是我想要的)。但不幸的是,图像也被截断了。

所以结果是这样的:

Hello w...

但我希望它看起来像:

Hello...##

也就是说,我希望图像附件不会被截断,它应该始终可见。

附件的原因是我希望图像始终位于字符串的末尾,因此当文本较短时,图像位于末尾,而当文本换行为多行时,我也希望图像位于结尾。尝试手动将图像“放在外面”是行不通的,因为文本不会被正确截断。

那么,有没有办法告诉NSAttributedString不要截断图像?

生成属性字符串的示例代码:

NSString *title;
NSMutableAttributedString *attributedString;
NSMutableParagraphStyle *paragraph;
NSDictionary *attributes;
NSTextAttachment *attachment;

paragraph = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
paragraph.hyphenationFactor = 1.0;
paragraph.lineBreakMode = NSLineBreakByTruncatingTail;

attributes = @{
    NSForegroundColorAttributeName : [self titleTextColor],
    NSParagraphStyleAttributeName : paragraph,
};

title = @"Hello world!";
attributedString = [[NSMutableAttributedString alloc] initWithString:title
                                                          attributes:attributes];

attachment = [[NSTextAttachment alloc] init];
attachment.image = [UIImage imageNamed:@"myImage"];
[attributedString appendAttributedString:[NSAttributedString attributedStringWithAttachment:attachment]];
[attachment release];

self.titleLabel.attributedText = attributedString;

[attributedString release];
[paragraph release];

编辑:这其中的一个重要部分(在上面的描述中有点丢失)是这个解决方案需要适用于多行文本。

4

5 回答 5

3

这是不容易实现的。您可以将段落样式设置为NSLineBreakByTruncatingMiddle,但结果将是最后一行在中间被截断 ( "Hel...rld!##")

所以你有几个选择。

  • 您可以重新设计,以便图像不会放在文本的末尾。
  • 您可以自己计算字符串的结尾,截断它并添加文本附件 - 做起来并不简单。
  • 使用 iOS7 的 Text Kit 来实现自定义截断逻辑。不幸的是,尽管在许多博客和 Apple 自己的文档UILabel中都写错了,但它不使用 TextKit 来呈现文本,而是使用 CoreText,从而使事情变得更加困难。我建议完全放弃并使用带有 Text Kit 支持UILabel的自定义实现。UIView您可以在此处找到一个使用 Text Kit 绘制文本的视图小示例,从而生成类似于标签的视图。现在您可以获得绘制字形的边界框,并正确放置图像。

这两种选择都不是完美的。您没有在最后一行的末尾提到图像是什么以及为什么需要它。我可能会选择选项 #1 并稍微更改设计,尽管 Text Kit 选项并不难实现。

于 2014-04-05T00:38:52.103 回答
3

我认为您不会通过“技巧”获得预期的结果。你必须做真正的工作:子类化NSTextContainer和覆盖-lineFragmentRectForProposedRect:atIndex:writingDirection:remainingRect:。这包括设置您自己的文本堆栈。

代码太长,这里就不贴了。但是文档中有一些示例。(OS X 的文档更丰富,IIRC。存在差异,但您可以使用它来基本了解这些部分。)所以这个答案仍然是一个指针。

因为你住在慕尼黑,我假设你懂德语。因此我想提一下,在我的书的第二部分,第 6 章中有一个代码示例,用于在中间的孔周围布局文本的视图。您可以通过在最后保留一个矩形来做同样的事情。

希望有帮助!

于 2014-04-06T10:19:23.533 回答
0

当您在 UILabel 中显示它时,您是否设置了

self.titleLabel.lineBreakMode = NSLineBreakByTruncatingMiddle
于 2014-04-04T23:51:51.693 回答
0

我想一种方法是获取完整字符串的长度,截断字符串的长度,然后生成一个新的 NSString Hello world!,截断差 + 3,然后...##在末尾添加。

它符合你的目的吗?

于 2014-04-04T23:02:09.820 回答
0

最近我也遇到了类似的情况,这是我最终得到的解决方案,它在我的情况下非常有效。

我有一个 UILabel ,我想显示一个带有图像的字符串。但是如果这个组合超过了 UILabel 宽度,我不得不截断字符串,然后在末尾附加图像。

我将在下面发布我的解决方案,这将对某人有所帮助。

  /// Provide a single line attibuted string with the image at the end of the string, and will truncate the string if the whole composision will exceed the frame size.
  /// - Parameters:
  ///   - string: The string which we are going to append the image
  ///   - rect: The UILabel rect of the string
  ///   - font: The Font to use in the attributed string
  ///   - imageName: The image name
  ///   - imageOrigin: The image location
  /// - Returns: The attibuted string with the image at the end. This string will be truncated if needed.
  private func getAttributedStringWithImage(string: String,
                                            rect: CGSize,
                                            font: UIFont,
                                            imageName: String,
                                            imageOrigin: CGPoint) -> NSAttributedString {
    
    // creating image to append at the end of the string
    let iconImage = UIImage(named: imageName)!
    let icon = NSTextAttachment()
    icon.bounds = CGRect(x: imageOrigin.x, y: imageOrigin.y, width: iconImage.size.width, height: iconImage.size.height)
    icon.image = iconImage
    let iconString = NSAttributedString(attachment: icon)
    
    // we will calculate the "attributed string length with image at the end" to deside whether we need to truncate
    // the string to append the image or not by looping the string
    var newStr = ""
    for char in string {
      newStr += String(char)
      
      let attStr = NSMutableAttributedString(string: (newStr + "..."), attributes: [ .font: font, .kern: 0.0 ])
      let stringRect = attStr.boundingRect(with: CGSize(width: CGFloat.greatestFiniteMagnitude, height: rect.height),
                                           options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil)
      
      if stringRect.width + imageOrigin.x +  iconImage.size.width + 5 > rect.width {
        newStr += "..."
        break
      }
    }
    
    let titleString = NSMutableAttributedString(string: newStr, attributes: [ .font: font, .kern: 0.0 ])
    titleString.append(iconString)
    
    return titleString
  }

并这样称呼它:

  let attributedText = getAttributedStringWithImage(string: contactEmailOrNumber,
                                                    rect: self.titleLabel.frame.size,
                                                    font: UIFont(name: "FontName-Bold", size: xx.0)!,
                                                    imageName: "ImageName",
                                                    imageOrigin: CGPoint(x: 6, y: -3))
于 2020-12-12T17:57:03.543 回答