在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堆栈:
// 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;
}
我认为这可以被视为我需要报告的Apple漏洞(除非我遗漏了一些明显的东西),但是如果有人有解决方法,我将非常感激。
答案 0 :(得分:6)
这是一个老版本的错误。在 推动限制iOS 7编程 一书中,作者在第377页写道:
在撰写本文时,Text Kit无法正确处理某些类型的排除路径。特别是,如果您的排除路径会强制某些行为空,则整个布局可能会失败。例如,如果您尝试以这种方式在圆圈中布置文本,则圆圈的顶部可能太小而无法包含任何文本,并且NSLayoutManager将无声地失败。此限制会影响NSTextContainer的所有用途。具体来说,如果lineFragmentRectForProposedRect:atIndex:writingDirection:remainingRect:永远返回一个空的CGRect,整个布局将失败。
也许你可以覆盖lineFragmentRectForProposedRect:atIndex:writingDirection:remainingRect
:
您的自定义NSTextContainer的解决方法。
答案 1 :(得分:3)
我也遇到过这个问题。如果您只需要排除textView顶部或底部的全宽空格,则可以使用textContainerInset
。
答案 2 :(得分:2)
变通方法建议:
在文字中添加换行符。
textView.text = "\n" + textView.text
答案 3 :(得分:1)
快速解决方法:
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
。文本在什么时候跳转到图像中?
编辑:如果您遇到问题,直到它能够容纳至少一个字符,则可以尝试调整文本框架。
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];
}
答案 4 :(得分:0)
我尝试用排除路径太努力了。
我的问题是,顶层排除路径从不起作用,它将内容推向顶部而不是中心,而底部内容的排除路径余量增加了一倍。
以下是对我有用的:
UITextView
通过将其放入init
中来与您的文本容器初始化:
super.init(frame: frame, textContainer: textContainer)
根据Daniel's answer,放在layoutSubviews
内:
self.textContainerInset = UIEdgeInsets.init(top: t, left: l, bottom: b, right: r)
在UITextView
子类init()
内或情节提要中,禁用滚动。
self.isScrollEnabled = false
有关更多详细信息,请阅读this super-helpful thread。