2017年8月20日日曜日

UITextViewのセンタリング

やりたいこと

ImageViewで描かれた吹き出しの中にTextViewを貼っている。
吹き出しの大きさが変更された時、中のテキストをそれに合わせ、吹き出しのできるだけ中心部分にセンタリングしたい。

必要なこと

TextViewのframeでなく、中のテキストが実際に表示されてる部分のrectを求め、それを元にセンタリングする。
CSSとかのpaddingに当たる値ですな。

TextViewの中のテキストの画面に表示されてる部分のみのrectはNSStringの以下の関数で得られる。
当然得られる値はTextViewのframe.sizeよりも小さくなる。

コード中のfdってのは俺のコードの都合なので無視して。
要は調べたいtextViewがどういうrectで、中のテキストはどんなフォント(サイズも含む)で画面に描画されるかを渡して調べてもらうわけだろう。

let rect = NSString(string: (fd!.textView.text)!)
                .boundingRect(with: (fd?.textView.frame.size)!,
                options: NSStringDrawingOptions.usesLineFragmentOrigin,
                attributes: [NSFontAttributeName : fd?.textView.font! as Any], context: nil)


textViewのframeサイズから得られたrectの値を引いて2で割れば上下/左右の均等なpaddingの値が求まる。
それをtextView.textContainerInset.〜に入れてやればいい。
textView.contentInset.〜と書かれてるサイトもあるけど、textContainerInsetじゃないとうまくいかないので注意。
contentInsetとはUITextViewの中にあるUIScrollViewに対するInsetだそうである。

var topPadding = (fd!.textView.bounds.size.height - rect.height * fd!.textView.zoomScale) / 2
topPadding = topPadding < 0.0 ? 0.0 : topPadding
var leftPadding = (fd!.textView.bounds.size.width - rect.width * fd!.textView.zoomScale) / 2
leftPadding = leftPadding < 0.0 ? 0.0 : leftPadding
//containerInset.topleft(上と左の余白)を設定
fd!.textView.textContainerInset.top = topPadding
fd!.textView.textContainerInset.bottom = topPadding / 2
fd!.textView.textContainerInset.left = leftPadding
fd!.textView.textContainerInset.right = leftPadding / 2

本来ならtopとbottom、leftとrightは同じ値を入れるべきだが、なんか微妙にテキストの位置が偏るみたいだったので、bottomとrightは値を半分にしたり、いろいろ変えてテストしてる。最適な値を探してみてほしい。
いいんだよ、理論がどうであろうと、見た目ちゃんとしてればw
また、描画の関係で文字が書かれるまでの空白とか少しできるけど、いいの。完璧じゃなくても。

参考サイト

0 件のコメント:

コメントを投稿