iOS
Swift
RxSwift

iMessageの入力UIのようなキーボードの表示と連動するUIを作る with RxSwift, RxKeyboard

概要

  • iMessage, LINEのようなテキスト入力UIでキーボードの表示に合わせて位置が動くViewを作る

イメージ

textinput.gif

サンプルリポジトリ

環境

  • Xcode 9.4
  • Swift 4.1
  • RxSwift 4.2
  • RxCocoa 4.2
  • RxKeyboard 0.8.3

簡単概要

  • RxKeyboardライブラリを使ってキーボードの高さを取得、テキスト入力UIのBottomLayoutConstraintに反映させる

ライブラリの導入

Podfile
  pod 'RxSwift'
  pod 'RxCocoa'
  pod 'RxKeyboard'
  pod 'RxOptional'

UIを用意する

ViewController(水色のところにテキスト入力UIを配置) テキスト入力UIView
スクリーンショット 2018-08-17 1.08.05.png スクリーンショット 2018-08-17 1.08.21.png

ViewController

ViewController.swift
import UIKit
import RxSwift
import RxCocoa
import RxKeyboard

class ViewController: UIViewController {

    @IBOutlet weak var messageInputView: MessageInputView!
    @IBOutlet weak var messageInputViewBottomConstraint: NSLayoutConstraint!

    private let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupMessageInputView()
    }

    private func setupMessageInputView() {
        RxKeyboard.instance.visibleHeight
            .drive(onNext: { [weak self] keyBoardHeight in
                self?.messageInputViewBottomConstraint.constant = -keyBoardHeight
                self?.view.layoutIfNeeded()
            })
            .disposed(by: disposeBag)
    }
}

ViewController.xib

z.gif

@IBOutlet weak var messageInputViewBottomConstraint: NSLayoutConstraint!
  • ViewControllerのconstraintとswiftコードを繋ぐ

簡単解説

        // RxKeyboard.instance <- シングルトンインスタンス
        RxKeyboard.instance.visibleHeight
            .drive(onNext: { [weak self] keyboardHeight in
                // keyboardの高さが変わるたびに呼ばれる
                self?.messageInputViewBottomConstraint.constant = -keyboardHeight
                // Viewの更新
                self?.view.setNeedsLayout()
                self?.view.layoutIfNeeded()
            })
            .disposed(by: disposeBag)

他にも

  • visibleHeightはキーボードが非表示の時に0を流しますが、 スクロールビューのcontentOffsetを調整する場合は向いていないので、0を流さないwillShowVisibleHeight を使うと良いらしいです :muscle:
// contentOffset
RxKeyboard.instance.willShowVisibleHeight
  .drive(onNext: { keyboardVisibleHeight in
    scrollView.contentOffset.y += keyboardVisibleHeight
  })
  .disposed(by: disposeBag)
  • 他にもkeyboardのframeを取得することもできるみたい(何に使うんだろう? :thinking:

more detail :arrow_down: