【解決】UITextViewのスクロールが初期状態で一番上にならない問題の解決方法

Swift4.0において、UITextViewに後からテキストを代入した場合、スクロールは最後の状態になってしまいました。

スクリプトに保持していた文章データをUITextViewに代入して表示するだけのシンプルな処理をしたかったのですが、かなり解決に時間をかけてしまったので備忘録。

UITextViewが初期状態で一番上にならない状態


@IBOutlet weak var textView: UITextView!
let textData = "表示するテキスト...(実際はスクロールが必要になる程の長さ)"

override func viewWillAppear(_ animated: Bool){
    textView.text = textData
}

このように単純に処理を書くと、textViewは一番下までスクロールされ、textDataの最後の部分を表示してしまいます。

ちょっと調べて改善してみた

ちょっと調べてみた結果、以下のようにすれば良いとのことでした。


@IBOutlet weak var textView: UITextView!
let textData = "表示するテキスト...(実際はスクロールが必要になる程の長さ)"

override func viewWillAppear(_ animated: Bool){
    textView.text = textData
    textView.setContentOffset(    // 追加
        CGPoint(x: 0, y: -textView.contentInset.top),
        animated: false)
}

しかし、上の方までスクロールした状態にはなったものの、なんか微妙な位置で止まってしまいました。
CGPointのyの値を0にしたりマイナスにしてみたりしたのですが、結果は変わらず。。。

めっちゃ調べて解決してみた

妥協する手もあったのですが、スクロールが微妙な位置で表示されるのはあまりにダサいな。。。と思いまして、めっちゃ調べてみました。

そして、解決策が見つかりました!

解決策1


override func viewWillAppear(_ animated: Bool){
    textView.text = textData
    self.view.layoutIfNeeded()    // 追加
    textView.setContentOffset(
        CGPoint(x: 0, y: -textView.contentInset.top),
        animated: false)
}

解決策2


override func viewDidLayoutSubviews() {    // 追加
    textView.setContentOffset(
        CGPoint(x: 0, y: -textView.contentInset.top),
        animated: false)
}
    

override func viewWillAppear(_ animated: Bool){
    textView.text = textData
    // 削除
}

テキストを代入してから

self.view.layoutIfNeeded()

を呼んでレイアウトし直すか、

もしくは

override func viewWillAppear(_ animated: Bool){ }

の中でUITextViewのオフセットを設定するか

このどちらかで無事解決しました!!

特に理由がなければ解決策1の方が簡単で良いのではないかと思います。

コメント