酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

AutoLayout上でTTTAttributedLabelのリンク(下線)を使うと、iOS 7の場合に下線が一部欠けてしまう問題

UILabelの表示を豪華(?)にするライブラリのひとつに「TTTAttributedLabel」があります。

長文の途中でリンクを貼りたい場合……たとえば Twitterでリプライをもらった時に@ch3coohの部分だけリンクを貼りたいというニーズがあるかと思います。

TTTAttributedLabelを使えば、アラ簡単!下記のようにaddLinkToURL()で本文中から該当部分だけにリンクを適用してくれます。

tweetLabel.attributedText = text

// ユーザーのURLを持っている場合リンクを貼る
if let url = userUrl {
    let range = NSMakeRange(0, text.string.characters.count)
    tweetLabel.addLinkToURL(NSURL(string: url), withRange: range)
}

しかし問題もあって、iOS 8以降だとリンクの下線部分まで綺麗に表示されるのですが、iOS 7の場合には複数行になるとリンクの下線の一部が消えてしまう問題にぶつかりました。

問題の発生している環境は以下の通りです。

  • Xcode 7.3.1 (iOS 9.3 SDK)
  • AutoLayoutでTTTAttributedLabelを配置している

今回対策としては、あまり手を入れずに修正するためにUILabelの表示領域を広げることにした。

TTTAttributedLabelを継承したTweetLabelクラスを作る

TTTAttributedLabelはCocoaPods経由でインストールしているので直接変更することはできません。ですので、TTTAttributedLabelを継承したTweetLabelクラスを作ります。

class TweetLabel: TTTAttributedLabel {
    
    var paddingInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)

    override func awakeFromNib() {
        if #available(iOS 8.0, *) {
            paddingInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        } else {
            paddingInsets = UIEdgeInsets(top: 0, left: 0, bottom: 2, right: 0)
        }
    }
    
    override func drawTextInRect(rect: CGRect) {
        let inRect = UIEdgeInsetsInsetRect(rect, paddingInsets)
        super.drawTextInRect(inRect)
    }
    
    override func intrinsicContentSize() -> CGSize {
        var size = super.intrinsicContentSize()
        size.height = size.height + paddingInsets.top + paddingInsets.bottom
        size.width = size.width + paddingInsets.left + paddingInsets.right
        return size
    }
}

これでiOSのときもリンクの下線まできちんと表示されるようになりました。

感想

この問題に対応するのに何が大変だったかというと、使用しているのがXcode 7.3.1だったので直接実機デバッグ・シミュレータデバッグともにiOS 7では使えません。バイナリを作成してからiOS 7端末にインストールして挙動を確認していました。

仮説を立てて一部修正してというのを繰り返すのがすごく手間のかかる作業になっていました。開発環境やCocoaPodsの関係でiOS 7のサポートが切れると嬉しいなと考えています。