Sponsor Link
環境&対象
- macOS Monterey 12.5 Beta
- Xcode 14.0 Beta2
- iOS 16.0 beta
TextField
SwiftUI でユーザーからの(主として Text)入力を受ける ビューに TextField があります。
この TextField の挙動を指定する オプションに、 onEditingChanged と onCommit 指定があります。
これらが iOS16/macOS13 で deprecated になり、別の書き方が必要となりますので、方法をまとめてみます。
TextField の onEditingChanged
TextField の初期化時に、onEditingChanged 引数に、closure を与えることができました。
TextField が編集中かどうか 変化した時に onEditingChanged が呼び出されます。
呼び出される時には、現在 編集中かどうかの フラグが渡されてきます。
そのフラグを使用することで、編集開始前/編集終了時に行いたい処理を行うことができました。
編集開始は、iOS と macOS でタイミングが異なります。
iOS では、TextField にフォーカスが与えられた時に呼び出されます。
macOS では、フォーカスが与えられただけでは呼び出されず、キー入力/削除 等の編集が開始された時に呼び出されます。(iOS16 Beta, macOS 12.5 Beta で確認)
編集終了とは、iOS/macOS 共に、TextField がフォーカスを失うことを意味します。(リターンキー押下では呼ばれません)
TextField の onCommit
TextField の初期化時に、onCommit 引数として 別の closure を渡すこともできます。
この onCommit は、ユーザーが リターンキーを押下したときに 呼び出されます。
使用例
以下は、onEditingChanged と onCommit を使用した簡単なサンプルです。

# 上記は、macOS 上のスナップショットですが、iOS でも動作します。
//
// ContentView.swift
//
// Created by : Tomoaki Yagishita on 2022/06/24
// © 2022 SmallDeskSoftware
//
import SwiftUI
struct ContentView: View {
@State private var str = "Hello"
@State private var world = "world"
var body: some View {
VStack {
TextField("TextField", text: $str, onEditingChanged: { editing in
if editing {
print("started to edit in textField")
} else {
print("finished textField editing")
}
}, onCommit: {
print("onCommit")
}).padding()
TextField("Dummy", text: $world).padding() // フォーカス移動のため
}
}
}
上記のコードを実行することで、onEditingChanged/onCommit がそれぞれ どのようなタイミングで呼ばれるかを確認できます。
# 2 つめの TextField は、観察対象の TextField のフォーカスを明示的に外せるように配置しています。
onEditingChanged/onCommit を置き換える
deprecated になる onEditingChagned と onCommit を置き換えていきます。
onEditingChange の代替
Apple のドキュメントによると、onEditingChanged の代わりに、FocusState と .focused を使いなさいと書いてあります。
Apple のドキュメントは、こちら。
先に挙げた 動作確認の例を書き換えていきます。
なお、iOS と macOS では onEditingChanged の振る舞いは異なりますが、iOS での onEditingChanged の振る舞いと同じになるように書いていきます。
//
// ContentView.swift
//
// Created by : Tomoaki Yagishita on 2022/06/24
// © 2022 SmallDeskSoftware
//
import SwiftUI
struct ContentView: View {
@State private var str = "Hello"
@State private var world = "world"
@FocusState var textFieldFocus: FocusedField?
enum FocusedField {
case Target
case Dummy
}
var body: some View {
VStack {
TextField("TextField", text: $str, onCommit: {
print("onCommit")
}).padding()
.focused($textFieldFocus, equals: .Target)
.onChange(of: textFieldFocus, perform: { newValue in
if newValue == .Target {
print("TextField got focus")
print("i.e. same with onEditingChanged with true")
} else {
print("TextField loose focus")
print("i.e. same with onEditingChanged with false")
}
})
TextField("Dummy", text: $world).padding() // フォーカス移動のため
}
}
}
FocusState/.focused/.onChange を組み合わせて onEditingChanged と同等の振る舞いを実現する実装の内訳は以下の通りです。
・FocusState を使って、変数 textFieldFocus: FocusedField を定義し、現在フォーカスされているビューを確認できるようにします。
・TextField には、.focused を付与し、フォーカスされているかどうかを textFieldFocus に同期します。
・textFieldFocus の変化を .onChange を使用して監視し、変化があった時に処理を実行します。
FocusState は、複数のビューのフォーカスを管理することもできるため、複数のビューのフォーカス変化について監視しようとすると、.onChange が複雑になっていきます。
onCommit の代替
Apple のドキュメントによると、onCommit の代わりに、onSubmit を使いなさいと書いてあります。
Apple のドキュメントは、こちら。
先の例を書き換えていきます。
//
// ContentView.swift
//
// Created by : Tomoaki Yagishita on 2022/06/24
// © 2022 SmallDeskSoftware
//
import SwiftUI
struct ContentView: View {
@State private var str = "Hello"
@State private var world = "world"
@FocusState var textFieldFocus: FocusedField?
enum FocusedField {
case Target
case Dummy
}
var body: some View {
VStack {
TextField("TextField", text: $str)
.padding()
.focused($textFieldFocus, equals: .Target)
.onChange(of: textFieldFocus, perform: { newValue in
if newValue == .Target {
print("TextField got focus")
print("i.e. same with onEditingChanged with true")
} else {
print("TextField loose focus")
print("i.e. same with onEditingChanged with false")
}
})
.onSubmit {
print("onCommit here")
}
TextField("Dummy", text: $world).padding() // フォーカス移動のため
}
}
}
onCommit の置き換えは、非常に簡単です。
onCommit の処理を View Modifier である .onSubmit に入れ替えると完了です。
まとめ
iOS16/macOS13 で deprecated になる TextField の onEditingChanged と onCommit の置き換えについてまとめました。
- onCommit は、.onSubmit に置き換える
- onEditingChanged は、FocusState/.focused/.onChange を使用して置き換える
- onEditingChanged の振る舞いは、iOS と macOS で異なるので注意する
説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。
SwiftUI おすすめ本
SwiftUI を理解するには、以下の本がおすすめです。
# 少し古くなってしまいましたが、基本的なところを理解できる 良書だと思います。
Sponsor Link