UITextViewの上にビューが乗っていて、UITextViewと一緒に気持ちよく動く。これがやりたかった。伝わる人には伝わるけれど、伝わらない人には伝わらない。UITextView面倒。。。いつもハマる。
でも、やってみましたー。とりあえず、とりいそぎ書いておきます。
完成形
とりあえずこんな感じになります。画面全体の大きさのUITextViewがあって、その上に黄緑のUIViewが乗っています。更にUIViewの上にボタンが有ります。UITextViewの上にビューがいくつもあるものの、全体としてスクロールが出来て、ボタンも押せます。更に、UITextViewの編集に入るタイミングと、編集が終わったタイミングで変な動きもしません。
ポイント
- textContainerInsetsを指定してテキストの領域を制限していること。contentInsetsでも同じようにテキストの領域を制限できるが、この場合、テキストのないところはタップできなくなってしまう。textContainerInsetsだとちゃんとタップできる。
キーボードが出てきた時の動きなどもあるので、キーボードの処理もついでに書いてあります。
コード
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var textView: UITextView!
@IBOutlet weak var textViewBottomConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
self.textView.textContainerInset = UIEdgeInsetsMake(100.0, 0.0, 0.0, 0.0)
let view = UIView(frame: CGRectMake(0.0, 0.0, CGRectGetWidth(self.textView.frame), 100.0))
view.backgroundColor = UIColor.greenColor()
self.textView.addSubview(view)
let button = UIButton.buttonWithType(.Custom) as UIButton
button.frame = CGRectMake(10.0, 10.0, 100.0, 44.0)
button.backgroundColor = UIColor.grayColor()
button.setTitle("Push Me!", forState: .Normal)
button.addTarget(self, action: "push:", forControlEvents: .TouchUpInside)
view.addSubview(button)
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
let notifications = \[UIKeyboardWillShowNotification, UIKeyboardWillChangeFrameNotification, UIKeyboardWillHideNotification\];
for notification in notifications {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "fitKeyboard:", name: notification, object: nil)
}
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
NSNotificationCenter.defaultCenter().removeObserver(self)
}
func fitKeyboard(notification: NSNotification) {
let userInfo = notification.userInfo
let duration = (userInfo?\[UIKeyboardAnimationDurationUserInfoKey\] as NSNumber).doubleValue
let curve = (userInfo?\[UIKeyboardAnimationCurveUserInfoKey\] as NSNumber).unsignedIntegerValue
let keyboardFrame = (userInfo?\[UIKeyboardFrameEndUserInfoKey\] as NSValue).CGRectValue()
let keyboardHeight = CGRectGetHeight(self.view.frame) - CGRectGetMinY(keyboardFrame)
self.textViewBottomConstraint.constant = keyboardHeight
let options = UIViewAnimationOptions(UInt(curve))
UIView.animateWithDuration(duration, delay: 0.0, options: options, animations: { () -> Void in
self.view.layoutIfNeeded()
}, completion: nil)
}
func push(sender: UIButton) {
println("button pushed!")
}
}
ざっと書いたので少し雑です。誰かの参考になれば。
課題
- 閉じるボタンの代わりに、StoryboardでDismiss Interactivelyの設定をした。これ、いいんだけど、閉じるときにキーボードのところでText viewが切れているのがかっこ悪い。(これ使わないでデリゲートで独自の書くともうちょっといい感じになる)
- UITextViewにコードでAutolayoutを書こうと思ったけどうまく行かなかった。ScrollView系だから左上右+高さ指定だけじゃダメなのかな。
- 本当はストーリーボード上だけで表現したかった。
サンプルコード
すいません、ちょっと雑なのですが。。。