環境
起きること
まずは動くコード
import SwiftUI struct ContentView: View { @State var text: String = "" @FocusState var focus: Bool var body: some View { TextEditor(text: $text) .focused($focus) .onChange(of: focus) { oldValue, newValue in print(oldValue, newValue) // => (false, true) } } }
当然ながらこのコードは動く。TextEditorをタップしてカーソルが表示されれば、focusが変更されてprintされる。
次に動かなくなるコード
import SwiftUI struct ContentView: View { @State var text: String = "" @FocusState var focus: Bool var body: some View { TextEditor(text: $text) .focused($focus) .onChange(of: focus) { oldValue, newValue in print(oldValue, newValue) // => Not work } // ↓追加 .safeAreaBar(edge: .bottom) { HStack { Image(systemName: "globe") } } } }
こうするとprintされないだけでなく、
Button("Close Keyboard") { focus = false }
といった、@FocusState経由でキーボードを閉じる処理も動かなくなる。.onChange が呼ばれないわけではなく、内部的にBindingされていなさそう。
対策
@FocusState が生まれる前の古き良き手法を使うしか無い。
キーボードを閉じるには、
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
キーボードの表示非表示でハンドリングしたいなら
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) { _ in // キーボード表示時 } .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in // キーボード非表示時 }
を使うことでなんとか迂回は可能。
感想
そもそも .safeAreaBar がiOS 26.0+のため、使えるアプリはかなり少なくハマることは少なそう。
同じ現象が自分の環境だけかと思って調べてみたけど、Redditでも同じ現象を話している人が居た。
ウキウキで最新APIを使って「これめっちゃ便利じゃーん」ってしてたら無駄に時間が消費されて悲しい。
さいごに
Apple Feedback Assistant経由でバグ報告はしておきました。