読者です 読者をやめる 読者になる 読者になる

テキストの一部をハイパーリンク化する

環境: Swift3
iOS10

f:id:xyk:20170518200531g:plain

UILabel ではなく UITextView の attributedText に NSLinkAttributeName をセットすることで簡単にできた。
クリック時にデフォルトでは Safari が起動して設定したURLのページが表示された。
クリック時の挙動を変更したい場合は UITextViewDelegate の
func textView(UITextView, shouldInteractWith: URL, in: NSRange, interaction: UITextItemInteraction)(iOS 10から)
または
func textView(UITextView, shouldInteractWith: URL, in: NSRange) (iOS7,8,9はこちら。iOS 10でDeprecated)
を実装して制御する。
今回は SFSafariViewController で開いてみた。

UILabel ではなく UITextView を使うことが簡単にできたわけだけど、UILabel に比べてちょっと面倒な点があった。
UILabel であればテキストが長くて複数行に渡る場合でも intrinsicContentSize が自動的に設定されるので AutoLayout で高さを指定しなくてもよいが、UITextView は高さを指定する必要があるので sizeThatFits で高さを計算して constant を更新する処理を入れている。

import UIKit
import SafariServices

class ViewController: UIViewController, UITextViewDelegate {

    @IBOutlet weak var textView: UITextView!
    @IBOutlet weak var textViewHeight: NSLayoutConstraint!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupTextView()
    }
    
    func setupTextView() {
        
        let text = "詳細はこちらをご覧ください"
        
        textView.delegate = self
        textView.isSelectable = true
        textView.isEditable = false
        textView.textContainer.lineFragmentPadding = 0
        textView.textContainerInset = .zero
        
        let attributedString = NSMutableAttributedString(string: text)
        let range = NSString(string: text).range(of: "こちら")
        
        attributedString.addAttribute(
            NSLinkAttributeName,
            value: "https://www.google.co.jp/",
            range: range)
        
        textView.attributedText = attributedString
        textView.linkTextAttributes = [NSForegroundColorAttributeName: UIColor.red]
        
        let textViewSize = textView.sizeThatFits(CGSize(width: UIScreen.main.bounds.width, height: .infinity))
        textViewHeight.constant = textViewSize.height
    }

    // MARK: - UITextViewDelegate
    
    // この Delegate の実装しない場合はデフォルトで URL を Safari で開く。
    func textView(_ textView: UITextView,
                  shouldInteractWith URL: URL,
                  in characterRange: NSRange,
                  interaction: UITextItemInteraction) -> Bool {
        
        // UIApplication.shared.open(URL)
        let controller = SFSafariViewController(url: URL)
        self.present(controller, animated: true)
        
        return false
    }

}