Ios 如果UITextView textContainer排除路径为全宽且位于textContainer顶部,则该路径将失败

Ios 如果UITextView textContainer排除路径为全宽且位于textContainer顶部,则该路径将失败,ios,uitextview,nstextcontainer,Ios,Uitextview,Nstextcontainer,在iOS 8中,我尝试将UIImageView添加为UITextView的子视图,类似于此处所示,但在图像下方有文本 我想使用排除路径,因为在其他设备上,我可能会根据屏幕大小对图像进行不同的定位 但是,如果用于创建排除路径的CGRect的Y原点为0,并且占据了textView的整个宽度,则排除会失败,并且文本显示在排除路径中(因此,文本显示在imageView后面,如该屏幕截图所示) 为了测试这一点,我使用“单视图”Xcode模板构建了一个简单的应用程序,包括以下内容: - (void)vie

在iOS 8中,我尝试将UIImageView添加为UITextView的子视图,类似于此处所示,但在图像下方有文本

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

但是,如果用于创建排除路径的CGRect的Y原点为0,并且占据了textView的整个宽度,则排除会失败,并且文本显示在排除路径中(因此,文本显示在imageView后面,如该屏幕截图所示)

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

- (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原点似乎也没有帮助

要使用自定义NSTextContainer,我在viewDidLoad()中设置UITextView堆栈,如下所示:

然后我在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(除非我遗漏了一些明显的东西),但如果有人有解决方法,我将不胜感激。

快速解决方法:

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

解决建议:

在文本中添加换行符


textView.text=“\n”+textView.text

这是一个老错误。在《推动限制iOS 7编程》一书中,作者在第377页写道:

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

也许您可以重写
lineFragmentRectForProposedRect:atIndex:writingDirection:remainingRect

您的自定义NSTextContainer的一部分,以解决此问题。

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

我尝试过排除路径

我的问题是顶级排除路径从来都不起作用,它将内容推向顶部而不是中心,而底部内容的边距是排除路径边距的两倍

以下是对我有效的方法:

  • 覆盖
    UITextView
  • 通过将其放入
    Init
    ,使用textcontainer初始化它:

    super.init(frame:frame,textContainer:textContainer)

  • 根据,放入
    布局子视图中

    self.textContainerInset=UIEdgeInsets.init(顶部:t,左侧:l,底部:b,右侧:r)

  • UITextView
    子类
    init()
    中或在情节提要中,禁用滚动

    self.isScrolEnabled=false


  • 有关更多详细信息,请阅读。

    不幸的是,这似乎也不起作用。在您将origin.x或origin.y调整为足够大以使字符开始沿左侧或顶部显示(取决于字体大小)之前,它会以完全相同的方式失败。已尝试调整textView框架,但这也会将imageView向下推。我还试着调整文本容器。大小。高度。。。但你不能,因为它是只读的。一个难看的解决方法可能是将imageView改为self.view的子视图(同时按照建议调整textView框架),并在textView滚动时调整imageView的位置。我还不确定我是否想这么做。无论如何,我真的很欣赏这些建议。我也尝试过调整textView框架,然后简单地调整imageView的Y原点以将其向上移动(给它一个负Y原点)-但是大多数图像应该在空白处。我也经历了同样的事情(iOS8)。对我来说,这好像是个苹果虫。如果有人想出了一个成功的解决办法,大声说出来!另一个解决方法是使用故事板布局,并针对不同的屏幕大小类别对图像、文本和约束进行不同的布局。您只需仔细检查排除路径,并确保textView.textContainer包含它的rect@GeoffH,
    textview.TextContainerSet
    textview.textContainer.lineFragmentPadding
    textview.contentInset
    也需要检查……太好了。。。我选择了一种不同的方法来解决这个问题,它也有自己的问题,这正是我所需要的。谢谢
    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;
    }
    
    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];
    }