如果全宽并位于textContainer顶部,则UITextView textContainer排除path将失败

在iOS 8中,我试图添加一个UIImageView作为UITextView的子视图,类似于这里显示的内容 – 但是图像下方的文本。

在这里输入图像说明

我想使用排除path,因为在其他设备上,我可能根据屏幕大小以不同的方式定位图像。

但是,如果用于创build排除path的CGRect的Y原点为0,并且占用了textView的全部宽度,则排除失败,并且文本显示在排除path中(这样文本显示在imageView,你可以在截图中看到)。

为了testing这个,我使用“single view”Xcode模板构build了一个简单的应用程序,其中包含以下内容:

- (void)viewDidLoad { [super viewDidLoad]; // set up the textView CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height); UITextView *textView = [[UITextView alloc] initWithFrame:frame]; [textView setFont:[UIFont systemFontOfSize:36.0]]; [self.view addSubview:textView]; textView.text = @"I wish this text appeared below the exclusion rect and not within it."; // add the photo CGFloat textViewWidth = textView.frame.size.width; // uncomment if you want to see that the exclusion path DOES work when not taking up the full width: // textViewWidth = textViewWidth / 2.0; CGFloat originY = 0.0; // uncomment if you want to see that the exclusion path DOES work if the Y origin isn't 0 // originY = 54.0; UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"photo_thumbnail"]]; imageView.frame = CGRectMake(0, originY, textViewWidth, textViewWidth); imageView.alpha = 0.7; // just so you can see that the text is within the exclusion path (behind photo) [textView addSubview:imageView]; // set the exclusion path (to the same rect as the imageView) CGRect exclusionRect = [textView convertRect:imageView.bounds fromView:imageView]; UIBezierPath *exclusionPath = [UIBezierPath bezierPathWithRect:exclusionRect]; textView.textContainer.exclusionPaths = @[exclusionPath]; } 

我也尝试了inheritanceNSTextContainer并重写-lineFragmentRectForProposedRect方法,但是调整Y原点似乎也没有帮助。

要使用自定义NSTextContainer,我在viewDidLoad()中设置了像这样的UITextView堆栈:

 // set up the textView stack NSTextStorage *textStorage = [[NSTextStorage alloc] init]; NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init]; [textStorage addLayoutManager:layoutManager]; CGSize containerSize = CGSizeMake(self.view.frame.size.width, CGFLOAT_MAX); CustomTextContainer *textContainer = [[CustomTextContainer alloc] initWithSize:containerSize]; [layoutManager addTextContainer:textContainer]; CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height); UITextView *textView = [[UITextView alloc] initWithFrame:frame textContainer:textContainer]; [textView setFont:[UIFont systemFontOfSize:36.0]]; [self.view addSubview:textView]; textView.text = @"I wish this text appeared below the exclusion rect and not within it."; 

然后我调整CustomTextContainer中的Y原点,就像这样…但是,

 - (CGRect)lineFragmentRectForProposedRect:(CGRect)proposedRect atIndex:(NSUInteger)characterIndex writingDirection:(NSWritingDirection)baseWritingDirection remainingRect:(CGRect *)remainingRect { CGRect correctedRect = proposedRect; if (correctedRect.origin.y == 0) { correctedRect.origin.y += 414.0; } correctedRect = [super lineFragmentRectForProposedRect:correctedRect atIndex:characterIndex writingDirection:baseWritingDirection remainingRect:remainingRect]; NSLog(@"origin.y: %f | characterIndex: %lu", correctedRect.origin.y, (unsigned long)characterIndex); return correctedRect; } 

我想这可能被认为是我需要报告的一个苹果bug(除非我错过了一些明显的东西),但如果有人有一个解决方法,将非常感激。

这是一个旧的bug。在“ 推动极限iOS 7编程 ”一书中,作者在第377页中写道:

在撰写本文时,Text Kit不能正确处理某些排除path。 特别是,如果您的排除path将强制某些行为空,整个布局可能会失败。 例如,如果你试图用这种方式在一个圆圈内放置文本,圆圈的顶部可能太小而不能包含任何文本,NSLayoutManager将自动失败。 此限制影响NSTextContainer的所有用途。 具体来说,如果lineFragmentRectForProposedRect:atIndex:writesDirection:remainingRect:返回一个空的CGRect,整个布局将失败。

也许你可以重载你的自定义NSTextContainer的lineFragmentRectForProposedRect:atIndex:writingDirection:remainingRect :来解决这个问题。

一个快速的解决方法:

 CGRect exclusionRect = [textView convertRect:imageView.bounds fromView:imageView]; if (exclusionRect.origin.x <= 0 && exclusionRect.origin.y <= 0 && exclusionRect.size.width >= textView.bounds.size.width) { exclusionRect.origin.x = 1; exclusionRect.origin.y = 1; exclusionRect.size.width -= 2; } 

你的图像仍然会绘制相同的图像,除非你使用的字体宽度为1px(我甚至不确定这是否可能,因为字距等),你的exclusionRect将保证小于整个宽度。

如果你允许实时移动你的矩形,我会很有兴趣知道你看到了什么样的结果。 附上UIPanGestureRecognizer并在屏幕上平移时更新您的exclusionRect 。 文字跳到图像的哪一点?

编辑 :如果您看到的问题,直到至less能够适应一个字符,也许尝试调整您的文本框架。

 if (exclusionRect.origin.x <= 0 && exclusionRect.origin.y <= 0 && exclusionRect.size.width >= textView.bounds.size.width) { frame.origin.y += CGRectGetMaxY(exclusionRect); frame.size.height -= CGRectGetMaxY(exclusionRect); [textView setFrame:frame]; } 

解决方法build议:

为您的文字添加换行符。

textView.text = "\n" + textView.text

我也遇到了这个问题。 如果您只需要排除textView顶部或底部的全部宽度空间,则可以使用textContainerInset