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系だから左上右+高さ指定だけじゃダメなのかな。
- 本当はストーリーボード上だけで表現したかった。
サンプルコード
すいません、ちょっと雑なのですが。。。