user16253584
user16253584

Reputation:

UITextView avoid text selection, but keep tappable links

I have a pop-up window, that shows terms of service & privacy policy for users, how to disable text selection but keep links tappable. screenshot If I set: SOLVED: By adding textViewDidChangeSelection method in UIViewDelegate and setting

textView.isSelectable = false
textView.isUserInteractionEnabled = true
textView.isSelectable = true

Links become uninteractable. How do I keep the link tappable and text not selectable?

My whole class:

//  HyperLinkTextView.swift

import SwiftUI

struct Hyperlink {
    var word: String
    var url: NSURL
}

struct HyperLinkTextView: UIViewRepresentable {
    
    private var text: String
    private var links: [Hyperlink]
    let textView = UITextView()
    
    init(text: String, links: [Hyperlink]) {
        self.text = text
        self.links = links
    }
    
    func makeUIView(context: Self.Context) -> UITextView {
        let attributedString = NSMutableAttributedString(string: text)
        links.forEach { hyperlink in
            let linkAttributes = [NSAttributedString.Key.link: hyperlink.url]
            
            var nsRange = NSMakeRange(0, 0)
            if let range = text.range(of: hyperlink.word) {
                nsRange = NSRange(range, in: text)
            }
            
            attributedString.setAttributes(linkAttributes, range: nsRange)
            attributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSNumber(value: 1), range: nsRange)
        }
        
        textView.isEditable = false
        textView.delegate = context.coordinator
        textView.attributedText = attributedString
        textView.linkTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor(Theme.colorClickables)]
        textView.isUserInteractionEnabled = true
        textView.isSelectable = true
    
        return textView
    }
    
    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.font = UIFont(name: "ArialMT", size: 18)
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }
    
    
    public class Coordinator: NSObject, UITextViewDelegate, NSLayoutManagerDelegate {
        
        weak var textView: UITextView?
            
        public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction, replacementText text: String) -> Bool {
            return true
        }
        
        func textViewDidChangeSelection(_ textView: UITextView) {
            if textView.selectedTextRange != nil {
                textView.delegate = nil
                textView.selectedTextRange = nil
                textView.delegate = self
            }
        }
    }
}

Upvotes: 2

Views: 826

Answers (1)

RTXGamer
RTXGamer

Reputation: 3712

Add this UITextViewDelegate textViewDidChangeSelection and comment out isEditable and isSelectable:

func textViewDidChangeSelection(_ textView: UITextView) {
    if textView.selectedTextRange != nil {
        textView.delegate = nil
        textView.selectedTextRange = nil
        textView.delegate = self
    }
}

Upvotes: 2

Related Questions