У меня была такая же проблема, как у оригинального постера.Я хотел, чтобы пользователь мог долго нажимать на UILabel, которая отображала список строк, разделенных запятыми, и извлекать подстроку, соответствующую месту касания между ближайшими запятыми.
Проблемав том, что UILabel не реализует протокол UITextInput, в противном случае реализация будет простой.
Мне не понравились какие-либо из предложенных обходных путей, которые я нашел, поэтому я решил найти собственное решение.После некоторых размышлений и исследований я понял, что, хотя UILabel не поддерживает UITextInput, UITextView поддерживает.Я не хотел заменять все UILabels в пользовательском интерфейсе на UITextViews, поэтому я подумал: «Почему бы программно не создать 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;
}
Единственное, что немного огорчает эту технику, это то, что вам нужно вручную настроить рендеринг в UITextView, отрегулировав область textContainerInset.В противном случае вы не получите точно такую же упаковку и размещение текста в UITextView, как в UILabel.В противном случае это достаточно общий код, который должен работать для всех остальных.