首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >UITextView的文本越界

UITextView的文本越界
EN

Stack Overflow用户
提问于 2014-02-20 02:51:47
回答 7查看 10.5K关注 0票数 19

我有一个不可滚动的UITextView,它的layoutManager maximumNumberOfLines设置为9,这很好用,但是,我似乎在NSLayoutManager中找不到一个方法来限制文本不能超出UITextView的框架。

举个例子,在这个截图中,光标在第9行(第一行在截图的顶部,所以忽略这一点)。如果用户继续键入新字符、空格或按return键,光标将继续离开屏幕,并且UITextView的字符串将继续变长。

我不想限制UITextView的字符数,因为外文字符的大小不同。

几个星期以来,我一直在努力解决这个问题;如果有任何帮助,我将非常感激。

CustomTextView.h

代码语言:javascript
运行
复制
#import <UIKit/UIKit.h>

@interface CustomTextView : UITextView <NSLayoutManagerDelegate>

@end

CustomTextView.m

代码语言:javascript
运行
复制
#import "CustomTextView.h"

@implementation CustomTextView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        self.backgroundColor = [UIColor clearColor];
        self.font = [UIFont systemFontOfSize:21.0];
        self.dataDetectorTypes = UIDataDetectorTypeAll;
        self.layoutManager.delegate = self;
        self.tintColor = [UIColor companyBlue];
        [self setLinkTextAttributes:@{NSForegroundColorAttributeName:[UIColor companyBlue]}];
        self.scrollEnabled = NO;
        self.textContainerInset = UIEdgeInsetsMake(8.5, 0, 0, 0);
        self.textContainer.maximumNumberOfLines = 9;
    }
    return self;
}

- (CGFloat)layoutManager:(NSLayoutManager *)layoutManager lineSpacingAfterGlyphAtIndex:(NSUInteger)glyphIndex withProposedLineFragmentRect:(CGRect)rect
{
    return 4.9;
}

@end

更新,仍未解析

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2014-02-26 17:21:55

我想这是一个更好的答案。每当调用shouldChangeTextInRange委托方法时,我们都会调用doesFit:string:range函数来查看结果文本高度是否超过视图高度。如果是这样,我们返回NO以阻止更改的发生。

代码语言:javascript
运行
复制
-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    FLOG(@" called");

    // allow deletes
    if (text.length == 0)
        return YES;

    // Check if the text exceeds the size of the UITextView
    return [self doesFit:textView string:text range:range];

}
- (float)doesFit:(UITextView*)textView string:(NSString *)myString range:(NSRange) range;
{
    // Get the textView frame
    float viewHeight = textView.frame.size.height;
    float width = textView.textContainer.size.width;

    NSMutableAttributedString *atrs = [[NSMutableAttributedString alloc] initWithAttributedString: textView.textStorage];
    [atrs replaceCharactersInRange:range withString:myString];

    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:atrs];
    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize: CGSizeMake(width, FLT_MAX)];
    NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];

    [layoutManager addTextContainer:textContainer];
    [textStorage addLayoutManager:layoutManager];
    float textHeight = [layoutManager
            usedRectForTextContainer:textContainer].size.height;
    FLOG(@" viewHeight = %f", viewHeight);
    FLOG(@" textHeight = %f", textHeight);

    if (textHeight >= viewHeight - 1) {
        FLOG(@" textHeight >= viewHeight - 1");
        return NO;
    } else
        return YES;
}

编辑确定如果更改文本格式,还需要添加一些检查。在我的例子中,用户可以更改字体或使其加粗,更改段落样式等。因此,现在这些更改中的任何一个都可能导致文本超出textView边界。

因此,首先您需要确保将这些更改注册到textViews undoManager。参见下面的示例(我只是复制了整个attributedString,以便在调用undo时可以将其放回原处)。

代码语言:javascript
运行
复制
// This is in my UITextView subclass but could be anywhere

// This gets called to undo any formatting changes 
- (void)setMyAttributedString:(NSAttributedString*) atstr {
    self.attributedText = atstr;
    self.selectedRange = _undoSelection;
}
// Before we make any format changes save the attributed string with undoManager
// Also save the current selection (maybe should save this with undoManager as well using a custom object containing selection and attributedString)
- (void)formatText:(id)sender {
    //LOG(@"formatText: called");
    NSAttributedString *atstr = [[NSAttributedString alloc] initWithAttributedString:self.textStorage];
    [[self undoManager] registerUndoWithTarget:self
                               selector:@selector(setMyAttributedString:)
                                 object:atstr];
    // Remember selection
    _undoSelection = self.selectedRange;

   // Add text formatting attributes
   ...
   // Now tell the delegate that something changed
   [self.delegate textViewDidChange:self];
}

现在检查代理中的大小,如果不合适,则撤消。

代码语言:javascript
运行
复制
-(void)textViewDidChange:(UITextView *)textView {
    FLOG(@" called");
    if ([self isTooBig:textView]) {
        FLOG(@" text is too big so undo it!");
        @try {
            [[textView undoManager] undo];
        }
        @catch (NSException *exception) {
            FLOG(@" exception undoing things %@", exception);
        }
    }
}
票数 8
EN

Stack Overflow用户

发布于 2014-02-22 03:18:45

对于文本视图,不建议使用boundingRectWithSize:options:attributes:context:,因为它不接受文本视图的各种属性(如填充),因此会返回不正确或不精确的值。

要确定文本视图的文本大小,请将布局管理器的usedRectForTextContainer:与文本视图的文本容器一起使用,以获得文本所需的精确矩形,并考虑所有必需的布局约束和文本视图怪癖。

代码语言:javascript
运行
复制
CGRect rect = [self.textView.layoutManager usedRectForTextContainer:self.textView.textContainer];

我建议在调用super实现之后,在processEditingForTextStorage:edited:range:changeInLength:invalidatedRange:中执行此操作。这将意味着通过提供您自己的文本容器并将其布局管理器设置为您的子类的实例来替换textview的布局管理器。这样,你就可以提交用户在文本视图中所做的更改,检查rect是否仍然可以接受,如果不是,则撤消。

票数 3
EN

Stack Overflow用户

发布于 2014-02-20 05:44:02

您将需要自己完成此操作。基本上它的工作原理是这样的:

  1. UITextViewDelegatetextView:shouldChangeTextInRange:replacementText:方法中查找当前文本的大小(例如NSString sizeWithFont:constrainedToSize: )。
  2. 如果大小大于您允许的大小,则返回FALSE,否则返回TRUE。如果用户键入的内容大于您允许的大小,
  3. 将向用户提供您自己的反馈。<代码>H29<代码>G210

编辑:由于sizeWithFont:已弃用,因此请使用boundingRectWithSize:options:attributes:context:

示例:

代码语言:javascript
运行
复制
NSString *string = @"Hello World"; 

UIFont *font = [UIFont fontWithName:@"Helvetica-BoldOblique" size:21];

CGSize constraint = CGSizeMake(300,NSUIntegerMax);

NSDictionary *attributes = @{NSFontAttributeName: font};

CGRect rect = [string boundingRectWithSize:constraint 
                                   options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)  
                                attributes:attributes 
                                   context:nil];
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21889657

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档