UITextViewの上にViewを載せて気持ちよくスクロールする

UITextViewの上にViewを載せて気持ちよくスクロールするUITextViewの上にビューが乗っていて、UITextViewと一緒に気持ちよく動く。これがやりたかった。伝わる人には伝わるけれど、伝わらない人には伝わらない。UITextView面倒。。。いつもハマる。

でも、やってみましたー。とりあえず、とりいそぎ書いておきます。

完成形

Shot

とりあえずこんな感じになります。画面全体の大きさの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系だから左上右+高さ指定だけじゃダメなのかな。
  • 本当はストーリーボード上だけで表現したかった。

サンプルコード

すいません、ちょっと雑なのですが。。。

Pocket
LINEで送る

You may also like...