Karakuri.com

Fintechではたらくアプリケーションエンジニアの技術録

XcodeとSwiftでUILabelのテキストのハイパーリンク化は気軽にはできない

HTMLライクなデザインでテキストにハイパーリンクを付けることになりました。

各項目を入力して送信ボタンを押してください。何か分からないことがありましたら、こちらからお問い合わせください

こんなケースですね。アンダーバーだけハイパーリンク化しないといけなかったんですね。これをUILabelを使って実現できるか色々調べて試してみました。

NSMutableAttributedStringを使う

NSMutableAttributedStringというクラスがあって、Stringに様々な属性を付加することができます。UILabelやUITextViewにはatributedTextというプロパティがあるので、このプロパティにNSMutableAttributedStringインスタンスをセットするとアンダーラインや文字色など変化あるテキストを表示することができます。WindowsやAndroidだとマークアップ言語に記述できるのですが、iOSだとコードビハインドで遅れていますね。まあ、しょうがないです。

let textView = UITextView()
textView.isSelectable = true
textView.isEditable = false

let text = "各項目を入力して送信ボタンを押してください。何か分からないことがありましたら、こちらからお問い合わせください。"
        
let attributedString = NSMutableAttributedString(string: text)
let range = NSString(string: text).range(of: "こちらからお問い合わせください")

attributedString.addAttribute(NSAttributedStringKey.link, value: "https://www.yahoo.co.jp/", range: range)
attributedString.addAttribute(NSAttributedStringKey.underlineStyle, value: 1, range: range)
        
textView.attributedText = attributedString

これで「こちらからお問い合わせください」だけハイパーリンク化されます。しかしこれはUITextViewを使った場合です。

UILabelのテキストをハイパーリンク化したい

実現できたとはいえ、たかがリンク付きのテキストを貼るためにUITextViewは大袈裟だと思うんです。シンプルにUILabelを使いたいですよね。そもそもUILabelにもattributedTextプロパティがあるのだから、下記のように書けば動くのではないかと思いますよね。

let label = UILabel()
let text = "各項目を入力して送信ボタンを押してください。何か分からないことがありましたら、こちらからお問い合わせください。"
        
let attributedString = NSMutableAttributedString(string: text)
let range = NSString(string: text).range(of: "こちらからお問い合わせください")

attributedString.addAttribute(NSAttributedStringKey.link, value: "https://www.yahoo.co.jp/", range: range)
attributedString.addAttribute(NSAttributedStringKey.underlineStyle, value: 1, range: range)
        
label.attributedText = attributedString

残念ながら動かないんですよね。

なぜUILabelではハイパーリンク化できないのか

実はUITextViewでもプロパティを変更するとUILabelと同様にハイパーリンクが動かなくなります。それがisSelectableプロパティです。最初のコードを下記のように書き換えるとハイパーリンクは動きません。

let textView = UITextView()
// textView.isSelectable = true
textView.isSelectable = false
textView.isEditable = false

let text = "各項目を入力して送信ボタンを押してください。何か分からないことがありましたら、こちらからお問い合わせください。"
        
let attributedString = NSMutableAttributedString(string: text)
let range = NSString(string: text).range(of: "こちらからお問い合わせください")

attributedString.addAttribute(NSAttributedStringKey.link, value: "https://www.yahoo.co.jp/", range: range)
attributedString.addAttribute(NSAttributedStringKey.underlineStyle, value: 1, range: range)
        
textView.attributedText = attributedString

選択できないからハイパーリンクのタップにも反応しないってことなんでしょうか…。そしてUILabelにはisSelectableプロパティがありません。選択不可能なUIコンポーネントなんですよね…。このためUILableではハイパーリンク化ができないというわけです。

どうしてもUILabelをハイパーリンク化したいなら

UILabelにUITapGestureRecognizerを設定してタップイベントを作ってそこでリンク処理を実装すればできるようです。
qiita.com
「これだけ」で実現できますって書いてありますが、WindowsやAndroidでマークアップ言語で済ませているのに慣れていると、たった1つのハイパーリンクにこんなにコード書かないといけないXcodeとSwiftに軽く絶望してしまいますね…。