キーボード処理
TextFieldを選択し、文字を入力するときにキーボードで隠れてしまい入力箇所が見れない場合があります。
キーボードの高さだけビュー全体を上にあげることで解決することが常套手段で、それをSwiftUIでも実装してみたのが今回の話です。
ObservableObjectのクラスで実装を行います。
実装
キーボードの制御を管理するファイルを作ってください。
KeyboardObserver.swift
import SwiftUI
import Combine
class KeyboardObserver: ObservableObject {
@Published var keyboardHeight: CGFloat = 0.0
// キーボードの監視開始
func addObserver() {
NotificationCenter
.default
.addObserver(
self,
selector: #selector(self.keyboardWillChangeFrame),
name: UIResponder.keyboardWillChangeFrameNotification,
object: nil)
}
// キーボードの監視終了
func removeObserver() {
NotificationCenter
.default
.removeObserver(self,
name: UIResponder.keyboardWillChangeFrameNotification,
object: nil)
}
// キーボードのフレーム検知処理
@objc
func keyboardWillChangeFrame(_ notification: Notification) {
if let endFrame = notification
.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue,
let beginFrame = notification
.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue {
let endFrameMinY: CGFloat = endFrame.cgRectValue.minY
let beginFrameMinY: CGFloat = beginFrame.cgRectValue.minY
self.keyboardHeight = beginFrameMinY - endFrameMinY
if self.keyboardHeight < 0 {
self.keyboardHeight = 0
}
}
}
}
これで下準備は完了です。
利用例(全体適用)
Sample.swift
struct HogeView: View {
@State var inputText = ""
@ObservedObject var keyboard = KeyboardObserver()
var body: some View {
VStack {
TextField("入力1", text: $inputText)
.onAppear{
self.keyboard.addObserver()
}.onDisappear{
self.keyboard.removeObserver()
}.padding(.bottom, keyboard.keyboardHeight)
}
}
}
onAppearとonDisappearでは、Viewが表示されたときにキーボードの高さを監視していて、Viewが非表示になった段階で監視を終わらせています。
※シュミレーターで表示させないとキーボードの挙動を確認できません
利用例(個別適用)
Sample.swift
struct HogeView: View {
@State var inputText = ""
@State var inputText_2 = ""
@State var inputText_3 = ""
@ObservedObject var keyboard = KeyboardObserver()
var body: some View {
VStack {
//1
TextField("入力1", text: $inputText)
//2
TextField("入力2", text: $inputText_2)
//3(ここに適用)
TextField("入力3", text: $inputText_3)
}
}
}
上記コードの三つ目のTextFieldにのみキーボードの操作を適用させたい場合は以下のように記述します。
Sample.swift
struct HogeView: View {
@State var inputText = ""
@State var inputText_2 = ""
@State var inputText_3 = ""
@ObservedObject var keyboard = KeyboardObserver()
var body: some View {
VStack {
//1
TextField("入力1", text: $inputText)
//2
TextField("入力2", text: $inputText_2)
//3(ここに適用)
TextField("入力3", text: $inputText_3, onEditingChanged: {
begin in
if begin {
self.keyboard.addObserver()
} else {
self.keyboard.removeObserver()
}
})
}.padding(.bottom, keyboard.keyboardHeight)
}
}
TextFieldのonEditingChangedでBoolで管理します。三つ目のTextFieldに対して入力操作が始まったときにキーボードの監視を開始し、入力が終わったら終了するようにしています。
まとめ
備忘録的な要素が強く、抜けがあると思いますがご容赦ください。
TextFieldがいくつもある場合に、個別適用を用いることが多くなりそうです。