iphone - Cómo interceptar hacer clic en el enlace en UITextView?
objective-c datadetectortypes (10)
¿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.
Y por favor no solo repitan el texto de la referencia de las clases de Apple, ciertamente ya lo he leído.
Gracias.
Actualización: desde ios10 ,
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction;
Desde ios7 y posteriores, UITextView
tiene el método de delegado:
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange *NS_DEPRECATED_IOS(7_0, 10_0, "Use textView:shouldInteractWithURL:inRange:forInteractionType: instead");*
para interceptar los clics a los enlaces. Y esta es la mejor manera de hacerlo.
Para ios6 y ios6 anteriores, una buena forma de hacerlo es UIApplication
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
Deberá implementar 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 inicia su aplicación, generalmente hay esta línea:
int retVal = UIApplicationMain(argc, argv, nil, nil);
El tercer parámetro es el nombre de clase para su aplicación. Entonces, reemplazando esta línea por:
int retVal = UIApplicationMain(argc, argv, @"MyApplication", nil);
Esto hizo el truco para mí.
Con Swift 3 y i0S 10, la forma más sencilla de interactuar con números de teléfono, direcciones URL o direcciones en UITextView
es usar UIDataDetectorTypes
. El siguiente código muestra cómo mostrar un número de teléfono en una 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, UIAlertController
un UIAlertController
.
Como alternativa, puede usar 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 atribuida, UIAlertController
un UIAlertController
.
Sin embargo, es posible que desee realizar alguna acción personalizada en lugar de hacer UIAlertController
un UIAlertController
al hacer clic en un número de teléfono. O quizás desee mantener un UIAlertController
para que aparezca y realice su propia acción personalizada al mismo tiempo.
En ambos casos, deberá hacer que su UIViewController
ajuste al protocolo UITextViewDelegate
e implementar 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, no UIAlertController
ningún UIAlertController
y en su lugar obtendrá la siguiente impresión en su consola:
tel: +33687654321
En iOS 7 o posterior
Puede usar el siguiente método Delegado UITextView:
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
La vista de texto llama a este método si el usuario pulsa o presiona prolongadamente 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:
Los enlaces en vistas de texto son interactivos solo 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.
No estoy seguro de cómo interceptaría 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.
No lo he intentado yo mismo, pero puedes intentar implementar la application:handleOpenURL:
método en tu aplicación delegada: parece que todas openURL
solicitudes de openURL
pasan por esta devolución de llamada.
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
Swift 4:
1) Cree la siguiente clase (UITextView subclasificado):
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) Dondequiera que configure su vista de texto, haga 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 el guión gráfico, asegúrese de que su vista de texto se vea así en el inspector de identidad del panel derecho:
Voila! Ahora obtienes el enlace tocar inmediatamente en lugar de cuando la URL debe interactuar con el método URL
Tengo contenido dinámico en la vista de texto, que puede contener un 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.
Lo siguiente es algo del código disparado.
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 de delegado anterior no se llama al tocar.
Saludos, Rohit Jankar
Versión Swift:
Su configuración estándar de UITextView debería verse más o menos así, no olvide delegar 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 que termine su clase, agregue 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
}
}
application:handleOpenURL:
se 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 forma 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.