TextViewをキーボードに隠されず、高さが動的に変わるようにする

多くのメッセージアプリが実装している、入力量に応じてTextViewのサイズが一定程度まで調整されるというあれです。 また、bottomにViewを配置してそこにTextViewを配置していると、ソフトウェアキーボードによってTextViewが隠されてしまうという問題も解決します。

基本的には【iOS】LINE風チャットUIを実装〜メッセージ入力欄編〜のSwift翻訳です。

パーツの配置

参考ページに従って、パーツを配置し、制約を設定してください。

以下コーディング

今回はコードはすべてViewControllerに対応するソースファイルに記述する前提とします。

キーボード表示時の浮き上がり動作

キーボードの表示・非表示の状態はNotificationで受け取ります。 まず、Observeが登録されているかを判別するため、ViewControllerの属性にisObservedを追加します。

    var isObserving = false

次に、viewWillAppear/viewWillDisappearに、Observerの登録/解除処理を記述します。

    override func viewWillAppear(animated: Bool) {
        // Viewの表示時にキーボード表示・非表示を監視するObserverを登録する
        super.viewWillAppear(animated)
        if(!isObserving) {
            let notification = NSNotificationCenter.defaultCenter()
            notification.addObserver(self, selector: "keyboardWillShow:"
                , name: UIKeyboardWillShowNotification, object: nil)
            notification.addObserver(self, selector: "keyboardWillHide:"
                , name: UIKeyboardWillHideNotification, object: nil)
            isObserving = true
        }
    }
    override func viewWillDisappear(animated: Bool) {
        // Viewの表示時にキーボード表示・非表示時を監視していたObserverを解放する
        super.viewWillDisappear(animated)
        if(isObserving) {
            let notification = NSNotificationCenter.defaultCenter()
            notification.removeObserver(self)
            notification.removeObserver(self
                , name: UIKeyboardWillShowNotification, object: nil)
            notification.removeObserver(self
                , name: UIKeyboardWillHideNotification, object: nil)
            isObserving = false
        }
    }

これらの記述に対応させて、キーボードが表示・非表示になったときに呼ばれるメソッドを実装します。

    func keyboardWillShow(notification: NSNotification?) {
        // キーボード表示時の動作をここに記述する
        let rect = (notification?.userInfo?[UIKeyboardFrameEndUserInfoKey] as NSValue).CGRectValue()
        let duration:NSTimeInterval = notification?.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as Double
        UIView.animateWithDuration(duration, animations: {
                let transform = CGAffineTransformMakeTranslation(0, -rect.size.height)
                self.view.transform = transform
            },completion:nil)
    }
    func keyboardWillHide(notification: NSNotification?) {
        // キーボード消滅時の動作をここに記述する
        let duration = (notification?.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as Double)
        UIView.animateWithDuration(duration, animations:{
            self.view.transform = CGAffineTransformIdentity
        },
            completion:nil)
    }

この記述によって、Viewの位置が調整され、ソフトウェアキーボードによってTextViewが隠されることがなくなります。

TextViewの高さが動的に変わるようにする

TextViewの高さを動的に変えるには、TextViewのDelegateを作成しTextViewのテキスト入力に応じて高さを調整するような処理を記述してやれば良いことになります。

そこで、TextViewとTextViewのHeightConstraintをOutlet接続します。

それぞれ、messageTextViewとmessageTextViewHeightという名前でOutlet接続しました。

@IBOutlet weak var messageTextViewHeight: NSLayoutConstraint!
@IBOutlet weak var messageTextView: UITextView!

今回はViewControllerのソースをそのままDelegateに流用するので、宣言を修正し、viewDidLoad処理のタイミングでdelegate登録をします。

class MessageViewController: UIViewController, UITextViewDelegate {
        messageTextView.delegate = self

では、処理を記述していきます。

入力の変更が行われた時の処理はtextViewDidChangeに記述します。

    func textViewDidChange(textView: UITextView) {
        let maxHeight = 80.0  // 入力フィールドの最大サイズ
        if(messageTextView.frame.size.height.native < maxHeight) {
            let size:CGSize = messageTextView.sizeThatFits(messageTextView.frame.size)
            messageTextViewHeight.constant = size.height
        }
    }

これで、TextViewのサイズが可変になりました。

参考