動的に生成されたテキストの大きなブロック内の特定のポイントで UITextView に UIButton を配置しようとしています。しかし、タイムリーに正確な座標を取得することは非常に困難です。attributedText は、事前に生成された NSAttributedString で設定されています。現在、NSLayoutManager のデリゲート メソッドにボタンを追加しています。これが最も論理的な場所に思えたからです。ただし、他のオプションも受け入れます。
関連するコードは次のとおりです。
func layoutManager(layoutManager: NSLayoutManager, didCompleteLayoutForTextContainer textContainer: NSTextContainer?, atEnd layoutFinishedFlag: Bool) {
let layoutManager = textView.layoutManager
let textContainer = textView.textContainer
let text = textView.attributedText
let inset = textView.textContainerInset.top
text.enumerateAttribute(NSAttachmentAttributeName, inRange: NSMakeRange(0, text.length), options: .LongestEffectiveRangeNotRequired) { (value, range, stop) in
if (value != nil) {
let boundingRect = layoutManager.boundingRectForGlyphRange(range, inTextContainer: textContainer)
let frame = CGRectMake(boundingRect.origin.x, boundingRect.origin.y+inset, boundingRect.size.width, boundingRect.size.height)
let button = UIButton()
button.setImage(UIImage(named: "canterbury_small_dark.png"), forState: .Normal)
self.textView.addSubview(button)
button.frame = frame
}
}
}
このコードはうまく機能しますが、UITextView の一番下までスクロールした場合にのみトリガーされます。ビューの一番下までスクロールしなくても、テキスト全体に対してすべてのレイアウトが確実に実行されるようにする方法はありますか? glyphRangeForTextContainer()、ensureLayoutForCharacterRange()など、「必要に応じてグリフの生成とレイアウトを実行する」と言うNSLayoutManagerのメソッドをいくつでも試しましたが、必要なことをしていないようです。
また、viewWillAppear() や viewDidLoad() など、コードの他の場所にボタンを追加しようとしました。ただし、ここで試してみると、レイアウト強制メソッドを呼び出した場合でも、boundingRectForGlyphRange() を呼び出すと、NSTextAttachment 画像の座標が返されますが、これは画像が実際に textView で終了する場所に正確ではないため、ボタンが非常に不正確な場所に配置されます。
テキストのレイアウトがどのように発生するかについて、何か重要なことが欠けていることは間違いありませんが、それが何であるかについては途方に暮れています。どんな助けでも大歓迎です!