UITextView'daki bağlantıya tıklamayı nasıl engelleyebilirim?


101

Kullanıcı UITextView'da otomatik olarak algılanan telefon bağlantısına dokunduğunda özel eylem gerçekleştirmek mümkün müdür? Lütfen bunun yerine UIWebView kullanmayı tavsiye etmeyin.

Ve lütfen sadece elma dersleri referansındaki metni tekrar etmeyin - kesinlikle zaten okudum.

Teşekkürler.

Yanıtlar:


144

Güncelleme: Gönderen ,

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

Nereden ve Daha sonra UITextViewtemsilci yöntemine sahiptir:

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange *NS_DEPRECATED_IOS(7_0, 10_0, "Use textView:shouldInteractWithURL:inRange:forInteractionType: instead");*

tıklamaları bağlantılara kesmek için. Ve bunu yapmanın en iyi yolu bu.

İçin ve daha önce bunu yapmanın güzel bir yolu, alt sınıflara ayırıp UIApplicationüzerine yazmaktır.-(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

openURL:Temsilcinizde uygulamanız gerekecek .

Şimdi, uygulamanın yeni alt sınıfınızla başlaması UIApplicationiçin projenizde main.m dosyasını bulun. Uygulamanızı önyükleyen bu küçük dosyada genellikle şu satır bulunur:

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

Üçüncü parametre, uygulamanızın sınıf adıdır. Yani, bu satırı şunun için değiştirir:

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

Bu benim için hile yaptı.


Sonunda gerçek cevap! Basit ve havalı fikir. Teşekkürler, işe yarıyor. Uzun zaman önceydi, bu yüzden zaten onsuz başardım. Yine de gelecekte yardımcı olabilir. Küçük bir düzeltme olsa da, başka daldaki süper sonucu döndürülmelidir: return [süper openURL: url];
Vladimir

2
Ayrıca UIApplicationopenURL uygulamasını kategorize edebilir ve değiştirebilirsiniz. Bu şekilde orijinal uygulamaya atıfta bulunmak zor (ancak imkansız değildir).
mxcl

1
Bilginize - GitHub'da bunu tam olarak uygulayan bir BrowserViewController yayınladım ve burada bir UIWebView içinden tıklanan bağlantıları destekledim: github.com/nbuggia/Browser-View-Controller--iPhone- .
Nathan Buggia

3
Bu, otomatik olarak biçimlendirilmiş telefon numaraları için değil, yalnızca web bağlantıları için işe yarıyor gibi görünüyor.
azdev

Uygulamamın temsilcisini hangi yöntemle belirleyebilirim?
ratsimihah

50

İOS 7 veya Üstünde

Aşağıdaki UITextView temsilci Yöntemini kullanabilirsiniz:

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

Metin görünümü, kullanıcı URL bağlantısına dokunursa veya uzun süre basarsa bu yöntemi çağırır. Bu yöntemin uygulanması isteğe bağlıdır. Varsayılan olarak, metin görünümü URL türünü işlemekten sorumlu uygulamayı açar ve ona URL'yi iletir. Bu yöntemi, mevcut uygulama içindeki bir web görünümünde URL'deki web içeriğini görüntülemek gibi alternatif bir eylemi tetiklemek için kullanabilirsiniz.

Önemli:

Metin görünümlerindeki bağlantılar, yalnızca metin görünümü seçilebilir ancak düzenlenemezse etkileşimlidir. Diğer bir deyişle, UITextView’un değeri, seçilebilir özellik YES ve isEditable özelliği HAYIR ise.


Bunu UITextViewDelegate'e eklemelerine sevindim.
2014

Maalesef hala kullanarak bitireceğiz UIWebViewbazı diğer metin yapmak istiyorsanız bağlantı ve URL değil kendisi. Etiketinin hala bu durumda gitmek için en iyi yoldur. <a>
MLQ

Başkalarının bunu görmesi durumunda, artık başka bir metni bağlantı yapabilirsiniz.
Schemetrical

10

Swift 3 için

textView.delegate = self

extension MyTextView: UITextViewDelegate {

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

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

veya hedef> = IOS 10 ise

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

7

Swift 5 ve iOS 12 ile, aşağıdaki üç kalıptan birini kullanarak bir UITextView.


# 1. UITextView'In dataDetectorTypesözelliğini kullanma .

A'daki telefon numaraları, url'ler veya adreslerle etkileşimin en basit yolu özelliği UITextViewkullanmaktır dataDetectorTypes. Aşağıdaki örnek kod, nasıl uygulanacağını gösterir. Bu kodla, kullanıcı telefon numarasına dokunduğunda bir UIAlertControlleraçılır.

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let textView = UITextView()
        textView.text = "Phone number: +33687654321"
        textView.isUserInteractionEnabled = true
        textView.isEditable = false
        textView.isSelectable = true
        textView.dataDetectorTypes = [.phoneNumber]
        textView.isScrollEnabled = false

        textView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(textView)
        textView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        textView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
    }

}

# 2. Kullanma UITextViewDelegatebireyin textView(_:shouldInteractWith:in:interaction:)yöntemi

UIAlertControllerKullanırken bir telefon numarasına dokunduğunuzda bir açılır pencere yapmak yerine bazı özel eylemler gerçekleştirmek istiyorsanız , protokole ve uygulamaya dataDetectorTypesuymanız gerekir . Aşağıdaki kod, nasıl uygulanacağını gösterir:UIViewControllerUITextViewDelegatetextView(_:shouldInteractWith:in:interaction:)

import UIKit

class ViewController: UIViewController, UITextViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        let textView = UITextView()
        textView.delegate = self
        textView.text = "Phone number: +33687654321"
        textView.isUserInteractionEnabled = true
        textView.isEditable = false
        textView.isSelectable = true
        textView.dataDetectorTypes = [.phoneNumber]
        textView.isScrollEnabled = false

        textView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(textView)
        textView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        textView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
    }

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

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

}

# 3. kullanılması NSAttributedStringveNSAttributedString.Key.link

Alternatif olarak, özniteliği için NSAttributedStringbir kullanabilir ve ayarlayabilirsiniz.Aşağıdaki örnek kod, bunun olası bir uygulamasını gösterir. Bu kodla, kullanıcı ilişkilendirilmiş dizeye dokunduğunda bir açılır.URLNSAttributedString.Key.linkUIAlertController

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let attributedString = NSMutableAttributedString(string: "Contact: ")
        let phoneUrl = NSURL(string: "tel:+33687654321")! // "telprompt://+33687654321" also works
        let attributes = [NSAttributedString.Key.link: phoneUrl]
        let phoneAttributedString = NSAttributedString(string: "phone number", attributes: attributes)
        attributedString.append(phoneAttributedString)

        let textView = UITextView()
        textView.attributedText = attributedString
        textView.isUserInteractionEnabled = true
        textView.isEditable = false
        textView.isSelectable = true
        textView.isScrollEnabled = false

        textView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(textView)
        textView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        textView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
    }

}

6

Swift versiyonu:

Standart UITextView kurulumunuz böyle bir şeye benzemelidir, delege ve dataDetectorTypes'i unutmayın.

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)

Dersiniz bittikten sonra şu parçayı ekleyin:

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

Swift 4:

1) Aşağıdaki sınıfı oluşturun (alt sınıflı 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) Metin görünümünüzü kurduğunuz her yerde, şunu yapın:

//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")
    }
}


Film şeridi kullanıyorsanız, metin görünümünüzün sağ bölme kimlik denetçisinde şöyle göründüğünden emin olun:
görüntü açıklamasını buraya girin



Voila! Artık, URL'nin URL yöntemiyle etkileşime girmesi gerektiği zaman yerine, bağlantıya hemen dokunuluyor.


ayrıca: url'nin işlenmesini istemiyorsanız, sadece shouldInteractWith yöntemini yanlış döndürecek şekilde ayarlayın
Josh O'Connor

Bunun bir bağlantıya dokunmadığınızda ne olacağı gibi bir dizi sorunu olduğunu düşünün. Yani, sıfır döndürüldüğü için metin görünümünün artık normal çalışacağını düşünmüyorum. Seçim, bir bağlantıya dokunduğunuzda da değişecektir, çünkü bu durumda, self döndürülür.
Drew McCormack

benim için harika çalışıyor, ihtiyaçlarınız için bu tür vakaları halletmeniz gerekiyor
Josh O'Connor

zayıf var linkDetectDelegate: QuickDetectLinkTextViewDelegate?
maslovsa

@vyachaslav benim için değil, yanlış bir şey yapıyor olmalısın
Josh O'Connor

0

Bunu kendim denemedim, ancak application:handleOpenURL:uygulama temsilcinize yöntemi uygulamayı deneyebilirsiniz - tüm openURLtalepler bu geri aramadan geçiyor gibi görünüyor .


0

Algılanan veri bağlantısını nasıl keseceğinizden veya ne tür bir işlevi çalıştırmanız gerektiğinden emin değilsiniz. Ancak ne aradığınızı biliyorsanız, metin alanında bir test / tarama çalıştırmak için didBeginEditing TextField yöntemini kullanabilirsiniz. Örneğin ### - ### - #### biçimini karşılayan metin dizelerini karşılaştırmak gibi, veya "www" ile başlayın. bu alanları yakalamak için, ancak metin alanları dizesini incelemek için küçük bir kod yazmanız, ihtiyacınız olanı yeniden oluşturmanız ve ardından işlevinizin kullanımı için çıkarmanız gerekir. Bunun o kadar zor olacağını sanmıyorum, tam olarak ne istediğinizi daralttıktan ve ardından if () ifadesi filtrelerinizi ihtiyacınız olan şeyle çok özel bir eşleştirme modeline odakladıktan sonra.

Bu, kullanıcının didBeginEditing () 'i etkinleştirmek için metin kutusuna dokunacağını ima eder. Aradığınız kullanıcı etkileşimi türü bu değilse, yalnızca ViewDidAppear () veya ihtiyaca bağlı olarak başka bir tetikleyici Timer kullanabilir ve metin alanları dizesi boyunca ilerleyebilir, ardından sonunda metin alanı dizesini çalıştırabilirsiniz. oluşturduğunuz yöntemler, sadece Zamanlayıcıyı geri kapatırsınız.


0

application:handleOpenURL:Başka bir uygulamanız açıldığında denir sizin bir düzeni Uygulamanızın desteklediği bir URL açarak uygulamayı. Uygulamanız bir URL'yi açmaya başladığında çağrılmaz.

Vladimir'in istediğini yapmanın tek yolunun UITextView yerine UIWebView kullanmak olduğunu düşünüyorum. Görünümünüzü kontrolör UIWebViewDelegate uygulamak olun, görünüm denetleyiciye UIWebView en temsilci ayarlayın ve görünümü denetleyicisi uygulamak webView:shouldStartLoadWithRequest:navigationType:açmak için [request URL]yerine uygulamayı çıkmaya ve Mobil Safari açmadan bir görünümde.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.