【问题标题】:How to truncate UITextView contents to fit a reduced size?如何截断 UITextView 内容以适应减小的大小?
【发布时间】:2011-08-14 15:27:41
【问题描述】:

我很难理解这个问题。

正如标题所示,我在 iPhone 应用程序的一个视图中有几个 UITextView。我正在以编程方式创建它们并成功地用文本填充该文本视图,但在某些情况下,我放入视图中的文本占用的空间比我为其分配的框架要多。在这种情况下,我希望将文本截断,但我不知道该怎么做。

我已经预定义了以下常量;

#define viewOriginX  20
#define viewOriginY 180

这是我的 UITextView 创建代码;

textViewOne = [[UITextView alloc] initWithFrame:CGRectMake(viewOriginX, viewOriginY + 65, 280, 45];
textViewOne.delegate = self;
textViewOne.scrollEnabled = NO;
textViewOne.contentInset = UIEdgeInsetsZero;
textViewOne.font = viewFont;
textViewOne.textColor = [UIColor blackColor];
textViewOne.textAlignment = UITextAlignmentLeft;
[self.view addSubview:textViewOne];

在某些情况下,我在这里有 15 到 20 行文本,我想将其截断为 2 行。

谁能帮助我朝着正确的方向前进?

提前致谢! :D

【问题讨论】:

  • UILabel 会代替你工作吗?在那里你可以设置 numberOfLines 属性,我认为它会具有你正在寻找的行为。
  • 我不明白为什么不...用户无论如何都无法编辑此文本,因此从该方法的 API 文档的外观来看,这可能会起作用。我会试一试的!

标签: ios iphone uitextview


【解决方案1】:

原答案(iOS 6 及以下)

遗憾的是,如果您需要可编辑视图,UILabelnumberOfLines 不会这样做。或者你想要UITextView 的(原生)垂直对齐方式。

这是一个NSString 类别,它根据矩形中的大小从字符串中删除单词:

@interface NSString (StringThatFits)
- (NSString *)stringByDeletingWordsFromStringToFit:(CGRect)rect
                                         withInset:(CGFloat)inset
                                         usingFont:(UIFont *)font
@end

@implementation NSString (StringThatFits)
- (NSString *)stringByDeletingWordsFromStringToFit:(CGRect)rect
                                         withInset:(CGFloat)inset
                                         usingFont:(UIFont *)font
{
    NSString *result = [self copy];
    CGSize maxSize = CGSizeMake(rect.size.width  - (inset * 2), FLT_MAX);
    CGSize size = [result sizeWithFont:font
                           constrainedToSize:maxSize
                               lineBreakMode:UILineBreakModeWordWrap];
    NSRange range;

    if (rect.size.height < size.height)
        while (rect.size.height < size.height) {

            range = [result rangeOfString:@" "
                                        options:NSBackwardsSearch];

            if (range.location != NSNotFound && range.location > 0 ) {
                result = [result substringToIndex:range.location];
            } else {
                result = [result substringToIndex:result.length - 1];
            }

            size = [result sizeWithFont:font
                            constrainedToSize:maxSize
                                lineBreakMode:UILineBreakModeWordWrap];
        }

    return result;
}
@end

对于UITextView,使用插入 8 来说明 UIKit 绘制它们的方式:

CGRect rect = aTextView.frame;
NSString *truncatedString = [theString stringByDeletingWordsFromStringToFit:rect
                                     withInset:8.f
                                     usingFont:theTextView.font];

更新答案(iOS 7)

现在UITextView 内部使用了TextKit,这更容易了。

与其截断实际字符串,不如将text(或attributedText)属性设置为整个字符串并截断容器中显示的文本量(就像我们对@ 987654331@):

self.textView.scrollEnabled = NO;
self.textView.textContainer.maximumNumberOfLines = 0;
self.textView.textContainer.lineBreakMode = NSLineBreakByTruncatingTail;

【讨论】:

  • 如果我的字符串类似于 "Hello\nWorld\nWassup ?"没有截断,它只会在末尾显示“Hello\nWorld”而没有“...”
  • 尝试设置行数。当我将它设置为 2 时它对我有用。很少有你会知道行数的情况,所以这对很多人没有帮助......
【解决方案2】:

您可以进行字符计数。例如,如果你有这样的 UITextField:

+--------------------+
|This is a string in |
|a text view.        |
+--------------------+

每行大约有 20 个字符。如果您知道该数字,您可以通过 -substringToIndex: 方法简单地截断您的字符串。

int maxCharacters = 40; // change it to your max
if([myString length] > maxCharacters) {
    myString = [myString substringToIndex:maxCharacters];
}

你也可以考虑UILabel。由于您只需要 2 行文本,UILabel 的 numberOfLines 属性可以解决您的问题。

【讨论】:

  • numberOfLines 是我所追求的,效果非常好!谢谢大家!
  • 这种方法的问题是某些字符比其他字符更易记号,因此如果您有动态文本,它将无法正常工作。
  • 不考虑\n,在超过字符数之前就可以超过垂直大小。
【解决方案3】:

因为 sizeWithFont:constrainedToSize:lineBreakMode: 在 iOS 7 中已被弃用,所以我做了一些更改:

- (NSString *)stringByDeletingWordsFromStringToFit:(CGRect)rect
                                     withInset:(CGFloat)inset
                                     usingFont:(UIFont *)font
{
    NSString *result = [self copy];
    CGSize maxSize = CGSizeMake(rect.size.width  - (inset * 2), FLT_MAX);
    if (!font) font = [UIFont systemFontOfSize:[UIFont systemFontSize]];
    CGRect boundingRect = [result boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: font, } context:nil];
    CGSize size = boundingRect.size;
    NSRange range;

    if (rect.size.height < size.height)
        while (rect.size.height < size.height) {

            range = [result rangeOfString:@" "
                                    options:NSBackwardsSearch];

            if (range.location != NSNotFound && range.location > 0 ) {
                result = [result substringToIndex:range.location];
            } else {
                result = [result substringToIndex:result.length - 1];
            }

            if (!font) font = [UIFont systemFontOfSize:[UIFont systemFontSize]];
            CGRect boundingRect = [result boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: font, } context:nil];
            size = boundingRect.size;
        }

    return result;

}

【讨论】:

  • 我能问一下您为什么不只使用 textView 的 textContainer 属性为您进行截断(根据我上面的修改答案)?我认为您想要使用此方法的唯一原因是您必须支持 iOS 6 或更早版本(在这种情况下,我深表同情!)
【解决方案4】:

这是我编写的用于截断字符串(按单词)以适应特定宽度和高度的代码:

- (NSString *)stringByTruncatingString:(NSString *)string toHeight:(CGFloat)height maxWidth:(CGFloat)width withFont: (UIFont *)font {

    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
    NSDictionary *attrDict = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, paragraphStyle, NSParagraphStyleAttributeName, nil];
    NSMutableString *truncatedString = [string mutableCopy];

    if ([string sizeWithAttributes: @{NSFontAttributeName: font}].height > height) {
        // this line is optional, i wrote for better performance in case the string is too big
        if([truncatedString length] > 150) truncatedString = [[truncatedString substringToIndex:150] mutableCopy];
        // keep removing the last word until string is short enough
        while ([truncatedString boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX) options:NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin attributes:attrDict context:nil].size.height > height) {
            NSRange wordrange= [truncatedString rangeOfString: @" " options: NSBackwardsSearch];
            truncatedString = [[truncatedString substringToIndex: wordrange.location] mutableCopy];
        }
        // add elipsis to the end
        truncatedString = [NSMutableString stringWithFormat:@"%@...",truncatedString];
    }
    return truncatedString;
}

用法:

NSString *smallString = [self stringByTruncatingString:veryBigString toHeight:65 maxWidth:200 withFont:[UIFont systemFontSize:14.0f]];

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-28
    • 2011-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-25
    • 1970-01-01
    • 2017-11-18
    相关资源
    最近更新 更多