2010-03-30 10 views
84

Es posible realizar una acción personalizada cuando el usuario toca el enlace del teléfono detectado automáticamente en UITextView. Por favor, no aconseje usar UIWebView en su lugar.Cómo interceptar hacer clic en el enlace en UITextView?

Y por favor no solo repita el texto de las clases de apple referencia - ciertamente ya lo he leído.

Gracias.

Respuesta

120

Actualización: A partir de iOS 7 y versiones posteriores UITextView tiene el método delegado:

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange 

para interceptar los clics a enlaces. Y esta es la mejor manera de hacerlo.

Para iOS 6 y versiones anteriores una buena manera de hacer esto es creando una subclase UIApplication y sobrescribir el -(BOOL)openURL:(NSURL *)url

@interface MyApplication : UIApplication { 

} 

@end 

@implementation MyApplication 


-(BOOL)openURL:(NSURL *)url{ 
    if ([self.delegate openURL:url]) 
     return YES; 
    else 
     return [super openURL:url]; 
} 
@end 

que se necesitan para poner en práctica openURL: en su delegado.

Ahora, para que la aplicación comience con su nueva subclase de UIApplication, ubique el archivo main.m en su proyecto. En este pequeño archivo que Bootstraps su aplicación, por lo general hay esta línea:

int retVal = UIApplicationMain(argc, argv, nil, nil); 

El tercer parámetro es el nombre de la clase para su aplicación.Entonces, reemplazando esta línea por:

int retVal = UIApplicationMain(argc, argv, @"MyApplication", nil); 

Esto me sirvió de algo.

+0

¡Por fin la respuesta real! Idea simple y genial Gracias, funciona Fue hace mucho tiempo, así que lo he logrado sin eso. Todavía puede ayudar en el futuro. Sin embargo, se debe devolver una corrección pequeña, resultado de super en la rama else: return [super openURL: url]; – Vladimir

+0

¡Genial! Hice la corrección sugerida. ¡Aclamaciones! – fsaint

+2

También podría categorizar 'UIApplication' y reemplazar la implementación de openURL. Aunque de esta manera es complicado (pero no imposible) hacer referencia a la implementación original. – mxcl

0

No lo he intentado pero puede intentar implementar el método application:handleOpenURL: en su delegado de aplicación - parece que todas las solicitudes openURL pasan por esta devolución de llamada.

0

No sé cómo interceptar el enlace de datos detectado o qué tipo de función necesita ejecutar. Pero es posible que pueda utilizar el método didBeginEditing TextField para ejecutar una prueba/exploración a través del campo de texto si sabe lo que está buscando ... como comparar cadenas de texto que cumplen con el formato ### - ### - ####, o comience con "www." para tomar esos campos, pero necesitaría escribir un pequeño código para oler a través de la cadena de campos de texto, reconocer lo que necesita y luego extraerlo para el uso de su función. No creo que esto sea tan difícil, una vez que haya definido exactamente qué es lo que quería y luego haya enfocado sus declaraciones if() hacia un patrón de coincidencia muy específico de lo que necesita.

Por supuesto, esto implica que el usuario va a tocar el cuadro de texto para activar el didBeginEditing(). Si ese no es el tipo de interacción con el usuario que buscaba, podría usar un temporizador de activación, que se inicia en ViewDidAppear() u otro según la necesidad y se ejecuta en la cadena de campos de texto, luego al final de ejecutar la cadena de campos de texto métodos que construiste, simplemente apaga el temporizador.

0

Se llama a application:handleOpenURL: cuando otra aplicación abre su aplicación abriendo una URL con un esquema compatible con su aplicación. No se llama cuando su aplicación comienza a abrir una URL.

Creo que la única manera de hacer lo que Vladimir quiere es usar un UIWebView en lugar de un UITextView. Haga que su controlador de vista implemente UIWebViewDelegate, configure el delegado de UIWebView en el controlador de vista y en el controlador de vista implemente webView:shouldStartLoadWithRequest:navigationType: para abrir [request URL] en una vista en lugar de salir de su aplicación y abrirla en Mobile Safari.

44

En iOS 7 o posterior

Usted puede utilizar el siguiente método UITextView delegado:

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange 

La vista de texto llama a este método si los grifos de usuario o largo presiona el enlace URL. La implementación de este método es opcional. De forma predeterminada, la vista de texto abre la aplicación responsable de manejar el tipo de URL y le pasa la URL. Puede utilizar este método para activar una acción alternativa, como mostrar el contenido web en la URL en una vista web dentro de la aplicación actual.

Importante:

Enlaces en las vistas de texto son interactivos sólo si la vista de texto es seleccionable pero no editable. Es decir, si el valor de UITextView la propiedad seleccionable es SÍ y la propiedad isEditable es NO.

+0

Me alegra que hayan agregado esto al UITextViewDelegate. – fsaint

+0

Desafortunadamente, usted todavía terminará usando 'UIWebView' si quiere hacer algún otro texto * el * enlace y no el URL en sí. La etiqueta '' sigue siendo la mejor manera de hacerlo en ese caso. –

3

versión Swift:

Su configuración UITextView estándar debe ser algo como esto, no se olvide el delegado y dataDetectorTypes.

var textView = UITextView(x: 10, y: 10, width: CardWidth - 20, height: placeholderHeight) //This is my custom initializer 
textView.text = "dsfadsaf www.google.com" 
textView.selectable = true 
textView.dataDetectorTypes = UIDataDetectorTypes.Link 
textView.delegate = self 
addSubview(textView) 

Después de su clase termina añadir esta pieza:

class myVC: UIViewController { 
    //viewdidload and other stuff here 
} 

extension MainCard: UITextViewDelegate { 
    func textView(textView: UITextView, shouldInteractWithURL URL: NSURL, inRange characterRange: NSRange) -> Bool { 
     //Do your stuff over here 
     var webViewController = SVModalWebViewController(URL: URL) 
     view.presentViewController(webViewController, animated: true, completion: nil) 
     return false 
    } 
} 
1

tengo contenido dinámico en vista de texto, que puede contener enlace. El shouldInteractWithURL se llama solo cuando el usuario hace una presión prolongada en el enlace pero no realiza una llamada al tocar el enlace. Por favor redirija si algún amigo tiene referencia.

A continuación se detallan algunos de los códigos atacados.

UITextView *ltextView = [[UITextView alloc] init]; 
[ltextView setScrollEnabled:YES]; 
[ltextView setDataDetectorTypes:UIDataDetectorTypeLink]; 
ltextView.selectable = YES; 
[ltextView setEditable:NO]; 
ltextView.userInteractionEnabled = YES; 
ltextView.delegate = (id)self; 
ltextView.delaysContentTouches = NO; 
[self.view addsubview:ltextview]; 

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange{ 

    [self.mActionDelegate userClickedOnImageLinkFromWebview:URL]; 

    NSLog(@"urls is :- %@",URL); 
    return FALSE; 
} 

El método delegado anterior no recibe ninguna llamada.

Saludos, Rohit Jankar

2

Con Swift 3 y 10 I0s, la forma más sencilla de interactuar con los números de teléfono, direcciones URL o direcciones en UITextView es utilizar UIDataDetectorTypes. El siguiente código muestra cómo mostrar un número de teléfono en un UITextView para que el usuario pueda interactuar con él.

import UIKit 

class ViewController: UIViewController { 

    // Link this outlet to a UITextView in your Storyboard 
    @IBOutlet weak var textView: UITextView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     textView.text = "+33687654321" 
     textView.isUserInteractionEnabled = true // default: true 
     textView.isEditable = false // default: true 
     textView.isSelectable = true // default: true 
     textView.dataDetectorTypes = [.phoneNumber] 
    } 

} 

Con este código, al hacer clic en el número de teléfono, un UIAlertController aparecerá.


Como alternativa, puede utilizar NSAttributedString:

import UIKit 

class ViewController: UIViewController { 

    // Link this outlet to a UITextView in your Storyboard 
    @IBOutlet weak var textView: UITextView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     let phoneUrl = NSURL(string: "tel:+33687654321")! // "telprompt://+33687654321" also works 
     let attributes = [NSLinkAttributeName: phoneUrl] 
     let attributedString = NSAttributedString(string: "phone number", attributes: attributes) 

     textView.attributedText = attributedString 
     textView.isUserInteractionEnabled = true // default: true 
     textView.isEditable = false // default: true 
     textView.isSelectable = true // default: true 
    } 

} 

Con este código, al hacer clic en la cadena con atributos, un UIAlertController aparecerá.


Sin embargo, es posible que desee realizar alguna acción personalizada en lugar de hacer un pop UIAlertController cuando se hace clic en un número de teléfono. O puede mantener un UIAlertController para que aparezca y realice su propia acción personalizada al mismo tiempo.

En ambos casos, deberá hacer que su UIViewController cumpla con el protocolo UITextViewDelegate e implemente textView(_:shouldInteractWith:in:interaction:). El siguiente código muestra cómo hacerlo.

import UIKit 

class ViewController: UIViewController, UITextViewDelegate { 

    // Link this outlet to a UITextView in your Storyboard 
    @IBOutlet weak var textView: UITextView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     textView.delegate = self 

     textView.text = "+33687654321" 
     textView.isUserInteractionEnabled = true 
     textView.isEditable = false 
     textView.isSelectable = true 
     textView.dataDetectorTypes = [.phoneNumber] 
    } 

    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool { 
     /* perform your own custom actions here */ 
     print(URL) 

     return false // return true if you still want UIAlertController to pop up 
    } 

} 

Con este código, al hacer clic en el número de teléfono, sin UIAlertController se abrirá y ustedes en lugar de obtener la letra siguiente en la consola:

tel: +33687654321

3

Para Swift 3

textView.delegate = self 

extension MyTextView: UITextViewDelegate 

    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool { 

     GCITracking.sharedInstance.track(externalLink: URL) 
     return true 
    } 
} 

o si el objetivo es> = IOS 10

func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool 
0

Swift 4:

1) Crear la siguiente clase (subclase UITextView):

import Foundation 

protocol QuickDetectLinkTextViewDelegate: class { 
    func tappedLink() 
} 

class QuickDetectLinkTextView: UITextView { 

    var linkDetectDelegate: QuickDetectLinkTextViewDelegate? 

    override init(frame: CGRect, textContainer: NSTextContainer?) { 
     super.init(frame: frame, textContainer: textContainer) 

    } 

    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
    } 

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { 
     let glyphIndex: Int? = layoutManager.glyphIndex(for: point, in: textContainer, fractionOfDistanceThroughGlyph: nil) 
     let index: Int? = layoutManager.characterIndexForGlyph(at: glyphIndex ?? 0) 
     if let characterIndex = index { 
      if characterIndex < textStorage.length { 
       if textStorage.attribute(NSLinkAttributeName, at: characterIndex, effectiveRange: nil) != nil { 
        linkDetectDelegate?.tappedLink() 
        return self 
       } 
      } 
     } 

     return nil 
    } 
} 


2) Donde quiera que configure su TextView, hacer esto:

//init, viewDidLoad, etc 
textView.linkDetectDelegate = self 

//outlet 
@IBOutlet weak var textView: QuickDetectLinkTextView! 

//change ClassName to your class 
extension ClassName: QuickDetectLinkTextViewDelegate { 
    func tappedLink() { 
     print("Tapped link, do something") 
    } 
} 


Si está utilizando guión gráfico, asegúrese de que su TextView es la siguiente con la derecha inspector de identidad panel:
enter image description here



Voila! Ahora obtiene el enlace toque inmediatamente en lugar de cuando la URL debe interactuar con el método URL

+0

también: si no quiere que se maneje la url, simplemente configure el método shouldInteractWith para que devuelva falso –

+0

Creo que esto tiene varios problemas, como lo que sucede cuando no toca un enlace. Es decir, no creo que la vista de texto funcione normalmente, ya que no se devuelve nada. La selección también cambiará cuando toque un enlace, porque en ese caso, se devuelve uno mismo. –

+0

funciona muy bien para mí, necesita manejar tales casos para sus necesidades –

Cuestiones relacionadas