【发布时间】:2010-12-07 03:11:46
【问题描述】:
我有 UILabel,其中有一些文字和 2 个月的名称,例如“一月和七月,阳光将是高峰” 我对 UILabel 进行了子分类并向其添加了触摸事件。 现在我想在用户触摸的文本下方获取单词,并找出用户是否触摸了 1 月/7 月。有可能吗?
【问题讨论】:
我有 UILabel,其中有一些文字和 2 个月的名称,例如“一月和七月,阳光将是高峰” 我对 UILabel 进行了子分类并向其添加了触摸事件。 现在我想在用户触摸的文本下方获取单词,并找出用户是否触摸了 1 月/7 月。有可能吗?
【问题讨论】:
我想您会在 UITextInputProtocol 的文档中找到您要查找的内容。
有关更多高级信息,请查看 Apple 的 Text, Web and Editing Guide,特别是在标题为“UITextInput 实现导览”的部分中。它讨论了如何在文本中创建索引位置,并询问触摸他们最接近的文本位置。
Apple 引用了一个名为 SimpleTextInput 的示例,但我似乎找不到它。我会继续寻找。
【讨论】:
我通过将透明的 UIViews 放在 UILabel 的顶部来解决这个问题,这些 UIViews 被连接以处理触摸事件。您可以通过计算文本相关部分的大小来调整命中区标签的位置和大小。这种方法还有一个优势,就是能够调整击球区的大小,使其更大,从而更容易用胖手指敲击。
【讨论】:
我已经解决了你的问题,只是为了好玩my blog。
我只是将UILabel 子类化并添加touchEnded,以识别触摸位置和字母位置。
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[touches allObjects] objectAtIndex:0];
CGPoint pos = [touch locationInView:self];
int sizes[self.text.length];
for ( int i=0; i<self.text.length; i++ )
{
char letter = [self.text characterAtIndex:i];
NSString *letterStr = [NSString stringWithFormat:@"%c", letter];
CGSize letterSize = [letterStr sizeWithFont:self.font];
sizes[i] = letterSize.width;
}
int sum = 0;
for ( int i=0; i<self.text.length; i++)
{
sum += sizes[i];
if ( sum >= pos.x )
{
[ _delegate didLetterFound:[ self.text characterAtIndex:i] ];
return;
}
}
}
希望这会有所帮助
干杯。
【讨论】:
我遇到了与原始海报类似的问题。我希望用户能够长按显示以逗号分隔的字符串列表的 UILabel,并提取与最近的封闭逗号之间的触摸位置相对应的子字符串。
问题在于 UILabel 没有实现 UITextInput 协议,否则实现起来很简单。
我不喜欢我发现的任何建议解决方法,因此我决定提出自己的解决方案。经过一番思考和研究,我意识到虽然 UILabel 不支持 UITextInput,但 UITextView 支持。我不想用 UITextViews 替换 UI 中的所有 UILabel,所以我想,“为什么不在后台以编程方式创建一个 UITextView,具有完全相同的文本呈现设置,并使用它的 UITextInput 方法将触摸点映射到所需的子字符串?”。
从我的角度来看,这被证明是理想的解决方案。
我将 UILongPressGestureRecognizer 附加到 UILabels 并在手势处理程序中调用以下函数:
-(NSString*)commaDelineatedTextAtTouchPosition:(UILongPressGestureRecognizer*)longPress
{
UILabel *gestureRecipient = (UILabel*)longPress.view;
UITextView *textRegionClone = [[UITextView alloc] initWithFrame:gestureRecipient.frame];
// tweak the text view's content area to get the same rendering (placement and wrapping)
textRegionClone.textContainerInset = UIEdgeInsetsMake(0.0, -5.0, 0.0, -5.0);
// copy the label's text properties
textRegionClone.text = gestureRecipient.text;
textRegionClone.font = gestureRecipient.font;
[textRegionClone setNeedsDisplay];
CGPoint loc = [longPress locationInView:gestureRecipient];
UITextPosition *charR = [textRegionClone closestPositionToPoint:loc];
id<UITextInputTokenizer> tokenizer = textRegionClone.tokenizer;
UITextRange *searchRange = [tokenizer rangeEnclosingPosition:charR withGranularity:UITextGranularityCharacter inDirection:UITextStorageDirectionBackward];
NSString *commaEnclosedText = @"";
if (searchRange != nil) {
NSString *tapChar = [textRegionClone textInRange:searchRange];
if ([tapChar isEqualToString:@","]) { // tapped right on a ","
// move the end of the range to immediately before the ","
searchRange = [textRegionClone textRangeFromPosition:searchRange.start toPosition:[textRegionClone positionFromPosition:searchRange.end offset:-1]];
}
UITextPosition *docStart = textRegionClone.beginningOfDocument;
// search back to find the leading comma or the beginning of the text
do {
searchRange = [textRegionClone textRangeFromPosition:[textRegionClone positionFromPosition:searchRange.start offset:-1] toPosition:searchRange.end];
commaEnclosedText = [textRegionClone textInRange:searchRange];
}
while (([searchRange.start isEqual:docStart] == NO) && ([commaEnclosedText characterAtIndex:0] != ','));
// now search forward to the trailing comma or the end of the text
UITextPosition *docEnd = textRegionClone.endOfDocument;
while (([searchRange.end isEqual:docEnd] == NO) && ([commaEnclosedText characterAtIndex:commaEnclosedText.length - 1] != ',')) {
searchRange = [textRegionClone textRangeFromPosition:searchRange.start toPosition:[textRegionClone positionFromPosition:searchRange.end offset:1]];
commaEnclosedText = [textRegionClone textInRange:searchRange];
}
commaEnclosedText = [[commaEnclosedText stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
return commaEnclosedText;
}
关于这种技术的唯一一点点 hacky 是您必须通过调整 textContainerInset 区域来手动调整 UITextView 中的呈现。否则,您不会在 UITextView 中获得与在 UILabel 中完全相同的文本包装和放置。否则,这是相当通用的代码,应该适用于其他任何人。
【讨论】:
- (void)tapped:(UITapGestureRecognizer *)tap
{
CGPoint location = [tap locationInView:_label];
NSDictionary *attribute = @{NSFontAttributeName: _label.font};
CGFloat width = 0;
for (int i = 0; i substringWithRange:NSMakeRange(i, 1)];
CGSize lettersize = [letterStr sizeWithAttributes:attribute];
width += lettersize.width;
if (width >= location.x ) {
NSLog(@"str: %@", letterStr);
break;
}
}
}
【讨论】: