UITextViewの設定がTextEditorに反映されるソースを求めて*1インターネットの海をさまよっていたときに出会ったproperty wrapper。
使ったことが無かったので試す。
開発環境
> xcodebuild -version Xcode 13.1 Build version 13A1030d
記事中のスクリーンショット: iPhone 13 Pro Max / iOS15.0
FocusStateとは
A property wrapper type that can read and write a value that SwiftUI updates as the placement of focus within the scene changes.
https://developer.apple.com/documentation/swiftui/focusstate
シーン内のフォーカスの配置が変更された時にSwiftUIが更新する値を読み書きできるproperty wrapper。
focused(_:)
フォーカス状況の取得
import SwiftUI struct ContentView: View { @FocusState private var addAttendeeIsFocused: Bool @State private var newAttendee: String = "" var body: some View { TextField("New Person", text: $newAttendee) .focused($addAttendeeIsFocused) Button("FOCUSED?") { // TextFieldがフォーカスされていればtrue print(addAttendeeIsFocused) } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
WWDC2021:What's new in SwiftUI でも動画上で触れられている。
強制フォーカス
@FocusState が付与されているBool型変数をTextEditorにバインドさせることで、その変数をtrueにすれば強制的にTextEditorにフォーカスを当てることが可能。
import SwiftUI struct ContentView: View { @FocusState private var isFocused: Bool @State private var text: String = "これはサンプルテキストです" var body: some View { Button("GO!") { isFocused = true } TextEditor(text: $text) .frame(width: 250, height: 250) .focused($isFocused) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
focused(_:equals:)
複数TextEditorのフォーカスを強制的に移動
ボタン押下でTextEditorのフォーカスを別のTextEditorに移す。
import SwiftUI struct ContentView: View { private enum Field: Int, Hashable { case first, second, third } @FocusState private var focusedField: Field? @State private var firstText: String = "" @State private var secondText: String = "" @State private var thirdText: String = "" var body: some View { ZStack(alignment: .center) { Color.yellow .ignoresSafeArea() VStack { TextEditor(text: $firstText) .frame(width: 250, height: 250) .focused($focusedField, equals: .first) TextEditor(text: $secondText) .frame(width: 250, height: 250) .focused($focusedField, equals: .second) TextEditor(text: $thirdText) .frame(width: 250, height: 250) .focused($focusedField, equals: .third) Button("CHANGE FOCUSED") { guard let focusedField = focusedField else { focusedField = .first return } switch focusedField { case .first: self.focusedField = .second case .second: self.focusedField = .third case .third: self.focusedField = .first } } } } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }