web-dev-qa-db-fra.com

La reconnaissance de la prise de lien UITextView est retardée

Dans une application iOS 7, j'ai un UITextView avec un lien, mais appuyer sur le lien ne se déclenche pas. Il ne répond qu'à un "tap and hold" gênant. Je veux qu'il réponde dès qu'un utilisateur appuie dessus, comme le fonctionnement d'un lien UIWebView lien. Voici ma configuration:

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:@"Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."];
    [text addAttribute:NSLinkAttributeName value:@"myurl://tapped" range:NSMakeRange(6, 16)];

    self.textView.attributedText = text;
    self.textView.editable = NO;
    self.textView.delaysContentTouches = NO;
}

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
{
    if ([[URL scheme] isEqualToString:@"myurl"])
    {
        // Handle tap

        return NO;
    }

    return YES;
}

La Apple Documentation de la méthode shouldInteractWithURL indique: "La vue texte appelle cette méthode si l'utilisateur appuie ou appuie longuement sur le lien URL". La pression longue fonctionne, mais le robinet ne semble pas fonctionner.

Est-ce que quelqu'un sait comment obtenir ceci pour répondre immédiatement?

35
lehn0058

Le UITextView est-il sélectionnable?. Essayez avec:

self.textView.selectable = YES;

Éditer:

Je commence à penser que peut-être un appui long est le seul moyen de le tirer contrairement à ce que Apple dit. Vérifiez cela lien , peut-être que cela aidera.

14
nnarayann

Si vous souhaitez toujours utiliser un UITextView natif, vous pouvez ajouter un identificateur de prise à votre affichage de texte et obtenir les attributs de chaîne à l'emplacement de prise. Lorsque vous trouvez un lien, vous pouvez l'ouvrir immédiatement.

J'ai écrit un Gist qui résout cela pour iOS 7/8. C'est une extension légère de UITextView qui transmet également -[UITextViewDelegate textView:shouldInteractWithURL:inRange:] et expose le module de reconnaissance interne des gestes de prise.

https://Gist.github.com/benjaminbojko/c92ac19fe4db3302bd28

Voici un petit exemple:L'exemple ci-dessous ne fonctionne que sur iOS 8. Voir l'essentiel ci-dessus pour la prise en charge d'iOS 7 + 8.

Ajoutez votre reconnaissance de robinet:

// ...

UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tappedTextView:)];
[myTextView addGestureRecognizer:tapRecognizer];
myTextView.selectable = YES; // otherwise the gesture won't recognize

// ...

Et ajoutez votre rappel:

- (void)tappedTextView:(UITapGestureRecognizer *)tapGesture {
    if (tapGesture.state != UIGestureRecognizerStateEnded) {
        return;
    }

    UITextView *textView = (UITextView *)tapGesture.view;
    CGPoint tapLocation = [tapGesture locationInView:textView];
    UITextPosition *textPosition = [textView closestPositionToPoint:tapLocation];
    NSDictionary *attributes = [textView textStylingAtPosition:textPosition inDirection:UITextStorageDirectionForward];

    NSURL *url = attributes[NSLinkAttributeName];

    if (url) {
        [[UIApplication sharedApplication] openURL:url];
    }
}

Et Swift version:

Reconnaissance du robinet:

let tapRecognizer = UITapGestureRecognizer(target: self, action: Selector("tappedTextView:"))
myTextView.addGestureRecognizer(tapRecognizer)
myTextView.selectable = true

Rappeler:

func tappedTextView(tapGesture: UIGestureRecognizer) {

        let textView = tapGesture.view as! UITextView
        let tapLocation = tapGesture.locationInView(textView)
        let textPosition = textView.closestPositionToPoint(tapLocation)
        let attr: NSDictionary = textView.textStylingAtPosition(textPosition, inDirection: UITextStorageDirection.Forward)

        if let url: NSURL = attr[NSLinkAttributeName] as? NSURL {
            UIApplication.sharedApplication().openURL(url)
        }

        }
38
Benjamin Bojko

Comme l'a mentionné nnarayann, CCHLinkTextView évite le problème de la reconnaissance de prise retardée. Cette bibliothèque implémente son propre identificateur de gestes et est désormais disponible en version 1.0.

7
Claus

Swift 4 solution


  • Gère les liens à l'aide de la reconnaissance des gestes tactiles
  • Que isSelectable soit true ou false, cela fonctionne

let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleLinkTap(_:)))
textView.addGestureRecognizer(tapRecognizer)

@objc func handleLinkTap(_ recognizer: UITapGestureRecognizer) {
    let tapLocation = recognizer.location(in: textView)
    guard
        let textPosition = textView.closestPosition(to: tapLocation),
        let url = textView.textStyling(at: textPosition, in: .forward)?[NSAttributedStringKey.link.rawValue],
        let urlString = (url as? String) ?? (url as? URL)?.absoluteString,
        urlString == "myurl"
    else { return }

    let url = URL(string: urlString)!
    // Do whatever you want with this URL, such as
    UIApplication.shared.openURL(url)
}
3
AamirR

Parfois, cela ne fonctionne pas sur le simulateur iOS ou ne fonctionne que si vous maintenez votre doigt appuyé.

Vous devez le tester sur un vrai appareil.

Et n'oubliez pas de le définir selectable.

2
Laszlo

Avez-vous essayé de définir textview.delaysContentTouches = NO;? Cela pourrait peut-être aider.

1
dezinezync

S'il n'y a aucune raison pressante d'utiliser un UITextView, tel qu'il y a un autre texte affiché, vous pouvez utiliser un UILabel combiné avec un UITapGestureRecognizer pour obtenir l'effet vous cherchez.

Sinon, vous pourriez plutôt utiliser un UIWebView réel.

1
dandan78