如果全宽并且位于textContainer顶部,则UITextView textContainer排除路径将失败 [英] UITextView textContainer exclusion path fails if full width and positioned at top of textContainer

查看:118
本文介绍了如果全宽并且位于textContainer顶部,则UITextView textContainer排除路径将失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在iOS 8中,我正在尝试添加UIImageView作为UITextView的子视图,类似于此处显示的内容 - 但图像下方的文字。

In iOS 8, I'm trying to add a UIImageView as a subview of a UITextView, similar to what's shown here - but with the text below the image.

我想做它使用排除路径,因为在其他设备上,我可能会根据屏幕大小不同地定位图像。

I want to do it using an exclusion path because on other devices, I might position the image differently depending on the screen size.

然而,如果CGRect用于创建排除,则存在问题path的Y原点为0,占用textView的全宽,排除失败,文本显示在排除路径中(因此文本显示在imageView后面,如截图中所示)。

However there's a problem where if the CGRect used to create the exclusion path has a Y origin of 0, and takes up the full width of the textView, the exclusion fails and the text appears within exclusion path (so that the text is shown behind the imageView, as you can see in that screenshot).

为了测试这个,我使用单一视图Xcode模板构建了一个简单的应用程序,具有以下内容:

To test this I built a simple app using the "single view" Xcode template, with the following:

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

我还尝试了子类化NSTextContainer并重写-lineFragmentRectForProposedRect方法,但调整了Y原点似乎没有帮助。

I also tried subclassing NSTextContainer and overriding the -lineFragmentRectForProposedRect method, but adjusting the Y origin there doesn't seem to help either.

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

To use the custom NSTextContainer, I set up the UITextView stack like this in viewDidLoad():

// 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原点......但是这个失败就像这样:

Then I adjust the Y origin in the CustomTextContainer like this... but this fails just as spectacularly:

- (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;
}

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

I suppose this could be considered an Apple bug that I need to report (unless I'm missing something obvious), but if anybody has a workaround it would be much appreciated.

推荐答案

这是一个老bug 。在 Pushing the Limits iOS 7 Programming 一书中,作者在第377页中写道:

This is an old bug.In the book Pushing the Limits iOS 7 Programming ,the author wrote this in page 377:


在撰写本文时,Text Kit无法正确处理某些类型的排除路径。特别是,如果您的排除路径会强制某些行为空,则整个布局可能会失败。例如,如果您尝试以这种方式在圆圈中布置文本,则圆圈的顶部可能太小而无法包含任何文本,并且NSLayoutManager将无声地失败。此限制会影响NSTextContainer的所有用途。具体来说,如果lineFragmentRectForProposedRect:atIndex:writingDirection:remainingRect:永远返回一个空的CGRect,整个布局将失败。

At the time of writing, Text Kit does not correctly handle some kinds of exclusion paths. In particular, if your exclusion paths would force some lines to be empty, the entire layout may fail. For example, if you attempt to lay out text in a circle this way, the top of the circle may be too small to include any text, and NSLayoutManager will silently fail. This limitation impacts all uses of NSTextContainer. Specifically, if lineFragmentRectForProposedRect:atIndex:writingDirection:remainingRect: ever returns an empty CGRect, the entire layout will fail.

也许你可以覆盖 lineFragmentRectForProposedRect:atIndex:writingDirection:remainingRect
您的自定义NSTextContainer以解决方法。

Maybe you can override lineFragmentRectForProposedRect:atIndex:writingDirection:remainingRect: of your custom NSTextContainer to workaround.

这篇关于如果全宽并且位于textContainer顶部,则UITextView textContainer排除路径将失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆