UITextView에서 링크 클릭을 차단하는 방법은 무엇입니까?


101

UITextView에서 사용자가 자동 ​​감지 된 전화 링크를 터치하면 사용자 지정 작업을 수행 할 수 있습니까? 대신 UIWebView를 사용하도록 조언하지 마십시오.

그리고 애플 클래스 레퍼런스의 텍스트를 반복하지 마십시오. 확실히 이미 읽었습니다.

감사.

답변:


144

업데이트 :부터 ,

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

에서 나중에 UITextView위임 메서드가 있습니다.

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

링크 클릭을 가로 챌 수 있습니다. 이것이 최선의 방법입니다.

에 대한 이전에이 작업을 수행하는 좋은 방법은 하위 클래스를 UIApplication만들고 덮어 쓰는 것입니다.-(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:대리인에서 구현해야합니다 .

이제 응용 프로그램을의 새 하위 클래스로 시작 UIApplication하려면 프로젝트에서 main.m 파일을 찾습니다. 앱을 부트 스트랩하는이 작은 파일에는 일반적으로 다음 줄이 있습니다.

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

세 번째 매개 변수는 애플리케이션의 클래스 이름입니다. 따라서이 줄을 다음으로 대체합니다.

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

이것은 나를 위해 트릭을했습니다.


마침내 진짜 대답! 간단하고 멋진 아이디어. 감사합니다. 오래 전 일이라 벌써없이 관리하고 있습니다. 앞으로도 여전히 도움이 될 수 있습니다. 그러나 약간의 수정이 있지만 super in else 분기의 결과가 반환되어야합니다. return [super openURL : url];
Vladimir

2
UIApplicationopenURL 구현을 분류 하고 대체 할 수도 있습니다 . 이렇게하면 원래 구현을 참조하는 것이 어렵지만 불가능하지는 않습니다.
mxcl 2010

1
참고로 GitHub에이를 완벽하게 구현하는 BrowserViewController를 게시했으며 여기에서 UIWebView 내에서 클릭 한 링크를 지원합니다. github.com/nbuggia/Browser-View-Controller--iPhone- .
Nathan Buggia 2011

3
이것은 자동 서식이 지정된 전화 번호가 아닌 웹 링크에서만 작동하는 것 같습니다.
azdev

내 애플리케이션의 델리게이트를 어떤 방법으로 설정할 수 있습니까?
ratsimihah

50

iOS 7 이상

다음 UITextView 대리자 메서드를 사용할 수 있습니다.

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

사용자가 URL 링크를 탭하거나 길게 누르면 텍스트보기에서이 메서드를 호출합니다. 이 메서드의 구현은 선택 사항입니다. 기본적으로 텍스트보기는 URL 유형을 처리하는 응용 프로그램을 열고 URL을 전달합니다. 이 메서드를 사용하여 현재 응용 프로그램 내의 웹보기에서 URL에 웹 콘텐츠를 표시하는 등의 대체 작업을 트리거 할 수 있습니다.

중대한:

텍스트보기의 링크는 텍스트보기를 선택할 수 있지만 편집 할 수없는 경우에만 대화 형입니다. 즉, UITextView의 값이 선택 가능한 속성이 YES이고 isEditable 속성이 NO 인 경우입니다.


나는 그들이 이것을 UITextViewDelegate에 추가해서 기쁩니다.
fsaint

불행히도 URL 자체가 아닌 UIWebView다른 텍스트 링크 로 만들고 싶다면 여전히 사용하게 될 것입니다. 이 경우 <a>태그는 여전히 가장 좋은 방법입니다.
MLQ 2014

다른 사람들이 이것을 볼 경우 이제 다른 텍스트를 링크로 만들 수 있습니다.
Schemetrical

10

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
    }
}

또는 타겟이> = IOS 10 인 경우

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

7

Swift 5 및 iOS 12에서는 다음 세 가지 패턴 중 하나를 사용하여 UITextView.


#1. UITextViewdataDetectorTypes속성을 사용 합니다.

전화 번호, URL 또는 주소와 상호 작용하는 가장 간단한 방법 UITextViewdataDetectorTypes속성 을 사용 하는 것 입니다 . 아래 샘플 코드는이를 구현하는 방법을 보여줍니다. 이 코드를 사용하면 사용자가 전화 번호를 탭하면 UIAlertController팝업이 나타납니다.

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. 사용 UITextViewDelegatetextView(_:shouldInteractWith:in:interaction:)방법을

당신이 대신이 만드는 일부 사용자 지정 작업을 수행 할 경우 UIAlertController사용하는 동안 전화 번호를 누를 때 팝업 dataDetectorTypes, 당신은 당신이 할 필요가 UIViewController준수 UITextViewDelegate프로토콜 및 구현 textView(_: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
    }

}

#삼. NSAttributedString및 사용NSAttributedString.Key.link

대안 으로 속성에 대해를 사용 NSAttributedString하고 설정할 수 있습니다. 아래 샘플 코드는 가능한 구현을 보여줍니다 .The sample code below shows a possible implementation of it. 이 코드를 사용하면 사용자가 속성 문자열을 탭하면 팝업이 나타납니다.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 버전 :

표준 UITextView 설정은 다음과 같아야합니다. 대리자와 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)

수업이 끝나면 다음 부분을 추가하십시오.

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

스위프트 4 :

1) 다음 클래스 (서브 클래 싱 된 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) 텍스트 뷰를 설정할 때마다 다음을 수행하십시오.

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


스토리 보드를 사용하는 경우 오른쪽 창 ID 검사기에서 텍스트보기가 다음과 같은지 확인합니다.
여기에 이미지 설명 입력



짜잔! 이제 URL이 InteractWith URL 메서드가 아닌 즉시 링크 탭을 얻습니다.


또한 : 당신이 처리 할 수없는 URL을 원하는 경우, 단지 false를 반환하는 shouldInteractWith 방법을 설정
조쉬 오코너

링크를 탭하지 않을 때 발생하는 일과 같은 많은 문제가 있다고 생각하십시오. 즉, nil이 반환되기 때문에 텍스트 뷰가 더 이상 정상적으로 작동하지 않을 것이라고 생각합니다. 링크를 탭하면 선택 항목도 변경됩니다.이 경우 self가 반환되기 때문입니다.
Drew McCormack

나를 위해 잘 작동, 당신은 당신의 필요를 위해 이러한 경우를 처리 할 필요가
조쉬 오코너

약한 var linkDetectDelegate : QuickDetectLinkTextViewDelegate?
maslovsa

@vyachaslav하지 나를 위해, 당신은 뭔가 잘못하고 있어야합니다
조쉬 오코너

0

직접 시도하지는 않았지만 application:handleOpenURL:응용 프로그램 대리자에서 메서드 를 구현할 수 있습니다. 모든 openURL요청이이 콜백을 통과 하는 것처럼 보입니다 .


0

감지 된 데이터 링크를 가로채는 방법 또는 실행해야하는 기능 유형이 확실하지 않습니다. 그러나 ###-###-#### 형식을 충족하는 텍스트 문자열을 비교하는 것과 같이 찾고있는 내용을 알고있는 경우 didBeginEditing TextField 메서드를 사용하여 텍스트 필드를 통해 테스트 / 스캔을 실행할 수 있습니다. 또는 "www"로 시작합니다. 이러한 필드를 가져 오려면 약간의 코드를 작성하여 텍스트 필드 문자열을 스니핑하고 필요한 것을 재구성 한 다음 함수 사용을 위해 추출해야합니다. 원하는 것을 정확히 좁힌 다음 if () 문 필터를 필요한 것과 매우 구체적인 일치 패턴으로 집중하면 이것이 그렇게 어려울 것이라고 생각하지 않습니다.

이것은 사용자가 didBeginEditing ()을 활성화하기 위해 텍스트 상자를 터치 할 것임을 의미합니다. 이것이 찾고 있던 사용자 상호 작용 유형이 아닌 경우 ViewDidAppear () 또는 기타 필요에 따라 시작하고 텍스트 필드 문자열을 통해 실행되는 트리거 타이머를 사용할 수 있으며 마지막에 텍스트 필드 문자열을 통해 실행합니다. 당신이 만든 방법은 타이머를 다시 끄면됩니다.


0

application:handleOpenURL:다른 응용 프로그램을 열 때라고 하여 하는 제도 앱 지원으로 URL을 열어 응용 프로그램을. 앱이 URL을 열기 시작할 때 호출되지 않습니다.

Vladimir가 원하는 것을 수행하는 유일한 방법은 UITextView 대신 UIWebView를 사용하는 것입니다. 뷰 컨트롤러가 UIWebViewDelegate를 구현하고, UIWebView의 델리게이트를 뷰 컨트롤러로 설정하고, 뷰 컨트롤러 에서 앱을 종료하고 Mobile Safari에서 여는 대신 뷰에서 webView:shouldStartLoadWithRequest:navigationType:열도록 구현 합니다 [request URL].

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.