SwiftyNote

主にSwiftな技術ブログ

UITextViewでハッシュタグとメンションを色を変えて表示とタップ検知をする

UITextViewで複数のハイライトを表現したい

最近の実装でSNSなどの普及でか#swiftなどのハッシュタグに加えて@rinovなど個別にハイライトして、タップしたときの挙動も柔軟に指定したい時がありました。 基本的には標準のNS***AttributeNameなどで該当の単語ごとにNSRangeを求めて属性を追加するのですが、この実装方法はかなり良くないと感じました。

Attribute Stringの問題点

UITextViewを用いて文字を装飾したい場合にはAttributedStringで属性と値を指定することで実現します。

例: UITextViewのテキストを赤くする

textView.text = "Hello World"
let attributedText = textView.mutableCopy() as? NSMutableAttributedString
attributedText.addAttribute(NSForegroundColorAttributeName, value: UIColor.red, range: NSMakeRange(0, 5))
textView.attributedText = attributedText

問題点

  • NS***AttributeNameというグローバルな値が属性のキーになっているため一覧性がない
  • UITextViewaddAttributeは値がAny型となっているため、例えばテキストカラーを設定するときにUIColorが設定されることが自明でありながら.redなどの省略が行えない。また、どんな値でも引数に渡せてしまい安全でない。
  • NSMutable~, NSRange, NS***AttributeNameなどObjective-Cの遺産を多く使用している。
  • ハイライトする単語のNSRangeを毎回算出するのが面倒である

上記の例では色を付けるだけでしたが多くの場合特定のキーワードを個別にハイライトしたりタップ時の挙動を柔軟に変更したいです。 UITextViewのプロパティとしてlinkTextAttributesというものがありますが、これはリンク属性の付いたテキストの見た目を一括で装飾の指定を行うことができますが、例えば、ハッシュタグは青色、メンションは赤色など個別に対応した属性の指定を行うことはできません。

// 単語ごとに個別の指定は行えない
textView.linkTextAttributes = [NSForegroundColorAttributeName: UIColor.red]

こういったObjective-CとSwiftの間でコーディングしている感があり、今後Swiftのバージョンアップした時に既存のコードを全て実装しなおすリスクも考えるとなかなか気が進みません。 そこで最近のリッチなテキストを柔軟にカスタマイズしたいと思い、UITextViewで実装したものをライブラリ化しました。

RegeributedTextView

https://github.com/rinov/RegeributedTextView

使い方はREADME.mdまたはhttp://qiita.com/rinov/items/da450d0ba9dffaaf8967にまとめました。

調べた限りでもTTTAttributedLabelなど有名なライブラリ(UILabel専用)がありますが、Swift製で正規表現 + 独自のTextAttributeプロパティを追加しているライブラリはありませんでした。複数単語のハイライトやタップした単語ごとに任意の処理をしたいなどがありましたら一度使用してみていただけると嬉しいです。 またGithubでIssueやPR等いただけるとさらに嬉しいです。

github.com