Objective c 带有文本附件和截断的属性字符串

Objective c 带有文本附件和截断的属性字符串,objective-c,nsattributedstring,nstextattachment,Objective C,Nsattributedstring,Nstextattachment,我有一个附加了图像的属性字符串(NSTextAttachment)。这工作正常,但我有一个截断的问题,我似乎无法解决 在本例中,假设字符串##是图像。所以我的字符串看起来像helloworld##。在段落样式上设置尾部截断 现在,如果空间受限,文本将被省略号截断(这正是我想要的)。但不幸的是,图像也被截断了 所以结果是这样的: Hello w... 但我希望它看起来像: Hello...## 也就是说,我希望图像附件不要被截断,它应该始终可见 附件的原因是我希望图像始终位于字符串的末尾,因此

我有一个附加了图像的属性字符串(
NSTextAttachment
)。这工作正常,但我有一个截断的问题,我似乎无法解决

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

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

所以结果是这样的:

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];

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

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


它符合您的目的吗?

当您在UILabel中显示它时,您设置了什么

self.titleLabel.lineBreakMode = NSLineBreakByTruncatingMiddle

这是不容易实现的。您可以将段落样式设置为<代码> NSLineBreakByTruncatingMiddle < /代码>,但结果是最后一行在中间被截断(<代码>)HEL…RLD! 所以你有几个选择

  • 您可以重新设计,使图像不会放置在文本的末尾
  • 您可以自己计算字符串的结尾,截断它并添加文本附件-这并不简单
  • 使用iOS7的文本工具包实现自定义截断逻辑。不幸的是,尽管许多博客和苹果自己的文档中都有错误的内容,
    UILabel
    不使用TextKit来呈现文本,而是使用CoreText,这让事情变得更加困难。我建议完全删除
    UILabel
    ,使用带有文本工具包支持的自定义
    UIView
    实现。您可以使用文本工具包找到视图图形文本的一个小示例,该示例生成类似于标签的视图。现在,您可以获得绘制轮廓的边界框,并正确放置图像

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

我认为使用“技巧”并不能达到预期的效果。您必须完成真正的工作:子类化和覆盖。这包括设置自己的文本堆栈

代码太长,无法在此处发布。但文档中有一些示例。(OSX的文档更丰富,IIRC。虽然存在差异,但您可以使用它来基本了解各个部分。)因此,这个答案仍然是一个指针

你住在慕尼黑,我想你懂德语。因此,我想提到的是,在我的第二章(第6章)中有一个代码示例,用于在中间的一个孔周围布局文本。您可以通过在末尾省去一个rect来完成同样的操作


希望有帮助

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

我有一个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))

对于一行字符串,像这样的东西可以工作,是的。不幸的是,我需要它来处理多行字符串。能详细说明一下吗?我用NSTextContainer做了一些实验,但我甚至无法让它跟踪多行字符串的结尾。那么,在被重写的
lineFragmentRectForProposedRect:atIndex:writingDirection:remainingRect:
中,我该怎么办呢?我的基本想法是,当您到达文本末尾,发现它不适合建议的rect时,只需减去右侧图像的空间(假设从左到右的写入方向)使文本系统缩短字符串。然后在右侧绘制图像。如果有足够的空间,您可以知道文本使用的最后一个位置并在那里绘制图像。要识别字符串的结尾,characterIndex应该会有所帮助。也许你必须从字符索引开始计算下一个字符的布局,看看它是否合适。好主意。到目前为止,这看起来是最精确的解决方案:如果可能,让它正常绘制,提供缩短的最后一行以正确绘制省略号,然后手动绘制图像。我今天或明天会玩这个。玩了一个多小时后,我不能让它做我想做的事。让NSTextStorage绘制两条线并截断最后一条线已经是一个问题
drawWithRect:options:context:
忽略文本容器中的值,并且让布局管理器绘制glyph始终绘制整个字符串而不截断。哦,天哪……对不起,那根本不能满足我的要求。输出完全不同。如果必须的话,CoreText可能是一个解决方案,但它需要大量的工作(和)。我不在乎为此实现我自己的
UIView