環境
TextFieldの日本語入力を確定するとカーソルが勝手に文末へ移動する
Mac向けのアプリで、Listの行としてTextFieldを配置するようなUIをSwiftUIで実装しました。
そして、動作確認でTextFieldに日本語を入力してエンターキーで確定させたところ、カーソルが文末へ勝手に移動する現象が起きました。
文末へ勝手に移動する様子がこちら。
実装は以下の通り。
struct ContentView: View { @State private var editable1: String = "日本語を[]してもカーソルは動かない" @State private var editable2: String = "日本語を[]するとカーソルが最後尾に移動する" var body: some View { VStack(alignment: .leading) { Text("ここはリストの外") TextField("something", text: $editable1) } List { VStack(alignment: .leading) { Text("ここはリストの中") TextField("something", text: $editable2) } .background(Color(.cyan)) } } }
日本語入力を確定させるたびにカーソルが文末へ移動するのは、さすがに困りました。というより、なぜただのTextFieldなのに移動してしまうのでしょう?
ちなみに、半角英数字だとエンターキーを押さないので、当然ですが、カーソルが文末へ移動することはありません。
OvservableObjectを使う、またはサブビューを使うと回避できた
いろいろ試した結果、2つの回避方法が見つかりました。
- OvservableObjectを使う
- サブビューを作り、それを使う
ちなみに、サブビューにOvservableObjectを渡す方法でも問題ありませんでした。
検討した実装は以下の通り。
struct ContentView: View { @State private var editable1: String = "日本語を[]してもカーソルは動かない" @State private var editable2: String = "日本語を[]するとカーソルが最後尾に移動する" @ObservedObject private var editable3 = ObservableEditable() // @ObservedObject private var editable4 = ObservableEditable() var body: some View { VStack(alignment: .leading) { Text("ここはリストの外") TextField("something", text: $editable1) } List { VStack(alignment: .leading) { Text("ここはリストの中") TextField("something", text: $editable2) } .background(Color(.cyan)) } // 回避できる List { VStack(alignment: .leading) { Text("ここはリストの中でObservableObjectを使う") TextField("something", text: $editable3.txt) Text("表示も[\(editable3.txt)]に変わる") } .background(Color(.yellow)) } // これも回避できる List { VStack(alignment: .leading) { Text("ここはリストの中のサブビューを使う") SubTextField() } .background(Color(.green)) } // ObservalObjectをサブビューに渡しても回避できる // List { // VStack(alignment: .leading) { // Text("ここはリストの中のサブビューを使う") // SubTextField(content: editable4) // } // .background(Color(.green)) // } } } // ObservableObjectを使う class ObservableEditable: ObservableObject { @Published var txt: String = "日本語を[]してもカーソルは動かない" } // サブビューを使う struct SubTextField: View { @State private var txt: String = "日本語を[]してもカーソルは動かない" var body: some View { TextField("something", text: $txt) } } // サブビューにObservableObjectを渡して使う //struct SubTextField: View { // @ObservedObject var content: ObservableEditable // // var body: some View { // TextField("something", text: $content.txt) // } //}
回避後の動きがこちら。
カーソルが文末へ勝手に移動する理由は不明
正直なところ、理由は分かりませんでした。
もしかしたら、私がTextFieldのドキュメントで何か見落としているのかもしれませんし、TextField自体のバグかもしれません。
実際、TextFieldの入力時に以下のエラーが出力されるのですが、これを調べてみるとXcode14からのバグだそうです。
This method should not be called on the main thread as it may lead to UI unresponsiveness.
StackOverflowの投稿より
このバグが改善されたときに、どうなるかですね。