UITextView с интерактивными ссылками, но без выделения текста
У меня есть UITextView, отображающий не редактируемый текст. Я хочу, чтобы текст автоматически анализировал ссылки, номера телефонов и т.д. Для пользователя, а также те, которые можно было бы щелкнуть.
Я не хочу, чтобы пользователь мог выделить текст, потому что я хочу переопределить эти длительные нажатия и взаимодействия с двумя нажатиями, чтобы сделать что-то другое.
Для того, чтобы ссылки обрабатывались в iOS7, переключатель Selectable должен быть включен для UITextView, но Selectable также позволяет выделять, чего я не хочу.
Я попытался переопределить жест LongPress, чтобы предотвратить выделение, но, похоже, отключил обычные нажатия на ссылки...
for (UIGestureRecognizer *recognizer in cell.messageTextView.gestureRecognizers) {
if ([recognizer isKindOfClass:[UILongPressGestureRecognizer class]]){
recognizer.enabled = NO;
}
if ([recognizer isKindOfClass:[UITapGestureRecognizer class]]){
recognizer.enabled = YES;
}
}
Есть много похожих потоков, но никто, кажется, не обращается к этому конкретному вопросу о связях с включенными, текст не выделяется.
Ответы
Ответ 1
Я работаю над одной и той же проблемой, и самое лучшее, что я мог сделать, это мгновенно очистить выбор, как только это будет сделано, добавив следующее в делегат UITextView:
- (void)textViewDidChangeSelection:(UITextView *)textView {
if(!NSEqualRanges(textView.selectedRange, NSMakeRange(0, 0))) {
textView.selectedRange = NSMakeRange(0, 0);
}
}
Обратите внимание на проверку, чтобы предотвратить рекурсию. Это в значительной степени решает проблему, потому что только выбор отключен - ссылки будут по-прежнему работать.
Другая тангенциальная проблема заключается в том, что текстовое представление по-прежнему станет первым ответчиком, который вы можете исправить, установив желаемого первого ответчика после установки выбранного диапазона.
Примечание: единственная видимая странность, которая остается, заключается в том, что нажатие и удержание вызывает увеличительное стекло.
Ответ 2
Я не уверен, что это работает для вашего конкретного случая, но у меня был аналогичный случай, когда мне нужны ссылки для текстового просмотра, чтобы быть кликабельными, но не хотел, чтобы был выбран текст, и я использовал текстовое представление для представления данных в CollectionViewCell.
Мне просто пришлось переопределить -canBecomeFirstResponder
и вернуть NO
.
@interface MYTextView : UITextView
@end
@implementation MYTextView
- (BOOL)canBecomeFirstResponder {
return NO;
}
@end
Ответ 3
Как я писал на другом посту, есть еще одно решение.
После нескольких тестов я нашел решение.
Если вы хотите, чтобы ссылки активны, и вы не включили выделение, вам необходимо изменить gestureRecognizers.
Например, есть 3 указателя LongPressGestureRecognizers. Один для клика по ссылке (minimumPressDuration = 0.12), второй для увеличения редактируемого режима (минимумPressDuration = 0,5), третий для выбора (минимумPressDuration = 0,8). Это решение удаляет LongPressGestureRecognizer для выбора и второго для масштабирования в режиме редактирования.
NSArray *textViewGestureRecognizers = self.captionTextView.gestureRecognizers;
NSMutableArray *mutableArrayOfGestureRecognizers = [[NSMutableArray alloc] init];
for (UIGestureRecognizer *gestureRecognizer in textViewGestureRecognizers) {
if (![gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {
[mutableArrayOfGestureRecognizers addObject:gestureRecognizer];
} else {
UILongPressGestureRecognizer *longPressGestureRecognizer = (UILongPressGestureRecognizer *)gestureRecognizer;
if (longPressGestureRecognizer.minimumPressDuration < 0.3) {
[mutableArrayOfGestureRecognizers addObject:gestureRecognizer];
}
}
}
self.captionTextView.gestureRecognizers = mutableArrayOfGestureRecognizers;
Протестировано на iOS 9, но оно должно работать на всех версиях (iOS 7, 8, 9).
Я надеюсь, что это помогает!:)
Ответ 4
Вот что сработало для меня.
Я не мог избавиться от увеличительного стекла, но это позволит вам сохранить возможность просмотра текста (так что вы можете использовать ссылки), но избавиться от всего пользовательского интерфейса, связанного с выбором. Проверено только на iOS 9.
Внимание! Swift ниже!
Сначала, подкласс UITextView
и включите эту функцию:
override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
return false
}
Это отключит меню копирования и т.д. Затем я включаю метод установки, который я вызываю из init, где я делаю кучу связанных с установкой задач. (Я использую только эти текстовые виды из раскадровки, таким образом, init init):
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
private func setup() {
selectable = true
editable = false
tintColor = UIColor.clearColor()
}
Выбирается = true, чтобы ссылки были недоступными, editable = false, потому что ссылки не отображаются в редактируемом текстовом представлении. Указание четкости tintColor
скрывает синие полосы, которые появляются в начале и конце выделения.
Наконец, в контроллере, использующем текстовое представление подкласса, убедитесь, что включен протокол UITextViewDelegate
, что делегат установлен textView.delegate = self
и реализует эту функцию делегата:
func textViewDidChangeSelection(textView: UITextView) {
var range = NSRange()
range.location = 0
range.length = 0
textView.selectedRange = range
}
Без этой функции панели выбора и контекстное меню будут отключены, но цветной фон по-прежнему останется за выбранным текстом. Эта функция избавляется от фона выбора.
Как я уже сказал, я не нашел способ избавиться от увеличительного стекла, но если они делают длинный кран в любом месте, кроме ссылки, ничто не останется позади, как только увеличительное стекло исчезнет.
Ответ 5
Это в значительной степени решает проблему, поскольку выбор текста отключен и скрывает увеличительное стекло - ссылки все равно будут работать.
func textViewDidChangeSelection(_ textView: UITextView) {
if let gestureRecognizers = textView.gestureRecognizers {
for recognizer in gestureRecognizers {
if recognizer is UILongPressGestureRecognizer {
if let index = textView.gestureRecognizers?.index(of: recognizer) {
textView.gestureRecognizers?.remove(at: index)
}
}
}
}
}
Примечание. Вместо удаления вы можете заменить распознаватель на свой желаемый.
Ответ 6
Хотя он, по общему признанию, хрупкий перед лицом возможных будущих изменений в реализации, подход Kubík Kašpar - единственный, который работал на меня.
Но (а) это может быть упрощено, если вы подклассом UITextView
и (b), если единственное взаимодействие, которое вы хотите разрешить, - это нажатие ссылки, вы можете сразу же распознать кран:
@interface GMTextView : UITextView
@end
@implementation GMTextView
- (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
// discard all recognizers but the one that activates links, by just not calling super
// (in iOS 9.2.3 a short press for links is 0.12s, long press for selection is 0.75s)
if ([gestureRecognizer isMemberOfClass:UILongPressGestureRecognizer.class] &&
((UILongPressGestureRecognizer*)gestureRecognizer).minimumPressDuration < 0.25) {
((UILongPressGestureRecognizer*)gestureRecognizer).minimumPressDuration = 0.0;
[super addGestureRecognizer:gestureRecognizer];
}
}
@end
Ответ 7
Здесь используется подкласс UITextView, который будет анализировать его распознаватели жестов и разрешать только те, которые взаимодействуют со связанным текстом (используя Swift 3).
class LinkTextView: UITextView {
override func gestureRecognizerShouldBegin(_ gesture: UIGestureRecognizer) -> Bool {
let tapLocation = gesture.location(in: self).applying(CGAffineTransform(translationX: -textContainerInset.left, y: -textContainerInset.top))
let characterAtIndex = layoutManager.characterIndex(for: tapLocation, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
let linkAttributeAtIndex = textStorage.attribute(NSLinkAttributeName, at: characterAtIndex, effectiveRange: nil)
// Returns true for gestures located on linked text
return linkAttributeAtIndex != nil
}
override func becomeFirstResponder() -> Bool {
// Returning false disables double-tap selection of link text
return false
}
}