iOS 4.3 中的 UITextView beginOfDocument 问题
Posted
技术标签:
【中文标题】iOS 4.3 中的 UITextView beginOfDocument 问题【英文标题】:Issue in UITextView beginningOfDocument in iOS 4.3 【发布时间】:2012-07-17 10:13:08 【问题描述】:以下是我在模拟器 ios 5+ 中使用和运行良好的代码,但在模拟器 4.3 中出现问题
UITextPosition *begin = [self.tvQuestion positionFromPosition:self.tvQuestion.beginningOfDocument offset:nrange.location];
以下是错误说明:
由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“-[UITextView beginOfDocument]: unrecognized selector sent to instance 0x5586050”
有人可以就此提出建议吗?提前致谢!
【问题讨论】:
【参考方案1】:自 iOS 3.2 起,UITextInput
协议包含 beginningOfDocument
选择器。
但是UITextView
从 iOS 5.0 开始只采用了UITextInput
。它以前符合UITextInputTraits
协议。
来源:在这里搜索UITextView http://developer.apple.com/library/ios/#releasenotes/General/iOS50APIDiff/index.html
如果您希望它在 iOS 4.x 及更高版本上运行,您必须在 iOS 4 上执行检查并自行计算:
CGRect newRect = CGRectZero;
if ([UITextView conformsToProtocol:@protocol(UITextInput)])
// iOS 5 and later
UITextPosition *begin = [self.tvQuestion positionFromPosition:self.tvQuestion.beginningOfDocument offset:nrange.location];
UITextPosition *end = [self.tvQuestion positionFromPosition:begin offset:nrange.length];
UITextRange *textRange = [self.tvQuestion textRangeFromPosition:begin toPosition:end];
newRect = [self.tvQuestion firstRectForRange:textRange];
else
// iOS 3.2 to 4.3
// Compute text position manually
#define TEXT_VIEW_PADDING 8.f
NSString *textContent = [self.tvQuestion.text substringToIndex:NSMaxRange(nrange)];
NSDictionary *ctFontDescriptorAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
self.tvQuestion.font.familyName, kCTFontFamilyNameAttribute,
// Uncomment for bold fonts
// [NSDictionary dictionaryWithObjectsAndKeys:
// [NSNumber numberWithInt:kCTFontBoldTrait], kCTFontSymbolicTrait,
// nil], kCTFontTraitsAttribute,
nil];
CTFontDescriptorRef ctFontDescriptor = CTFontDescriptorCreateWithAttributes((CFDictionaryRef)ctFontDescriptorAttributes);
CTFontRef ctFont = CTFontCreateWithFontDescriptor(ctFontDescriptor, self.tvQuestion.font.pointSize, NULL);
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:textContent
attributes:[NSDictionary dictionaryWithObjectsAndKeys:
(id)ctFont, kCTFontAttributeName,
nil]];
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attributedText);
CFRange globalRange = CFRangeMake(0, [attributedText length]);
CGRect textRect = CGRectInset((CGRect)CGPointZero, self.tvQuestion.contentSize, TEXT_VIEW_PADDING, TEXT_VIEW_PADDING);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, globalRange, CGPathCreateWithRect((CGRect)CGPointZero, textRect.size, NULL), NULL);
CFArrayRef lines = CTFrameGetLines(frame);
NSInteger nbLines = CFArrayGetCount(lines);
CGPoint *lineOrigins = calloc(sizeof(CGPoint), nbLines);
CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), lineOrigins);
CGFloat ascent = CTFontGetAscent(ctFont);
CGFloat descent = CTFontGetDescent(ctFont);
CGFloat leading = CTFontGetLeading(ctFont);
if (leading < 0)
leading = 0;
leading = floor(leading + 0.5);
CGFloat lineHeight = floor(ascent + 0.5) + floor(descent + 0.5) + leading;
CGFloat firstLineYOffset = 0.f;
for (NSInteger i = 0; i < nbLines; i++)
CTLineRef line = CFArrayGetValueAtIndex(lines, i);
CFRange lineRange = CTLineGetStringRange(line);
CGPoint lineOrigin = lineOrigins[i];
CGFloat ascent, descent, leading, width;
width = CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
if (i == 0)
firstLineYOffset = lineOrigin.y;
lineOrigin.y = (lineOrigin.y - firstLineYOffset) * -1.f;
if (nrange.location >= lineRange.location && nrange.location < lineRange.location + lineRange.length)
CGFloat secOffset;
CGFloat startOffset = CTLineGetOffsetForStringIndex(line, nrange.location, &secOffset);
CGFloat rectWidth;
if (nrange.location + nrange.length <= lineRange.location + lineRange.length)
CGFloat endOffset = CTLineGetOffsetForStringIndex(line, nrange.location + nrange.length, &secOffset);
rectWidth = endOffset - startOffset;
else
rectWidth = width - 5 - startOffset;
newRect = (CGRect)
lineOrigin.x + TEXT_VIEW_PADDING + startOffset,
lineOrigin.y + TEXT_VIEW_PADDING + i
,
rectWidth,
lineHeight
;
break;
free(lineOrigins);
CFRelease(frame);
CFRelease(framesetter);
CFRelease(ctFont);
CFRelease(ctFontDescriptor);
【讨论】:
谢谢。但是,解决这个问题的方法是什么。有什么想法吗? @Nats 我已经编辑了答案以进行可用性检查。现在,我猜你必须编写一些代码才能在 iOS 4 上执行相同的计算。 谢谢...但实际上我的问题是我想获取文本的矩形,下面是我在 iOS 5 中运行的代码。 UITextPosition *begin = [self.tvQuestion positionFromPosition:0 offset :nrange.location]; UITextPosition *end = [self.tvQuestion positionFromPosition:begin offset:nrange.length]; UITextRange *textRange = [self.tvQuestion textRangeFromPosition:begin toPosition:end]; CGRect newRect = [self.tvQuestion firstRectForRange:textRange];如何在 iOS 4 中做同样的事情是个问题 :) ? @Nats 我认为这会涉及到一些 CoreText 的东西。但是由于文本视图中的文本是由 WebKit 呈现的,因此很难获得完全相同的结果。 @Nats 我添加了一些代码来计算 iOS4 上的帧。这是相当重的东西,但应该返回一个接近firstRectForRange:
返回的帧【参考方案2】:
虽然 UITextView 不符合 iOS 4.x 上的 UITextInput 协议,但它的子视图可以。以下代码适用于 iOS 4.x 及更高版本。
UIView<UITextInput> *t = [textView.subviews objectAtIndex:0];
assert([t conformsToProtocol:@protocol(UITextInput)]);
// use t for the view conforming to UITextInput
UITextPosition *beginning = t.beginningOfDocument; // OK
【讨论】:
以上是关于iOS 4.3 中的 UITextView beginOfDocument 问题的主要内容,如果未能解决你的问题,请参考以下文章
iOS - 无法访问 UITableViewCell 类中的 UITextView 委托
如何在 iOS 11 中禁用 UITextView 中的拖动
UIModalPresentationFormSheet 中的 UITextView 冻结应用程序 iOS 10