원했던 결과물은 위와 같다. 안 보이던 TextField 를 보이게 함과 동시에 focus 되게 하여 키보드가 올라오도록 하는 것이다.
그러나 앱에서는 테스트와 다르게 위와 같은 상황이 펼쳐졌다.
@FocusState 가 iOS15 에서 도입된 개념이다보니 버그가 꽤 있는 것 같지만 자료는 많이 없다. 그래서 여러 테스트를 혼자 해보면서 문제를 일으키는 위치는 찾을 수 있었다. NavigationView 와 FocusState 와 if 에 있다.
잘 작동하는 테스트 코드는 아래와 같다. 간단하게 TextField 가 appear 됨과 동시에 focus 해주는 것이다.
import SwiftUI
struct ContentView: View {
@State private var str = ""
@State private var show = false
@FocusState private var focus: Bool
var body: some View {
// NavigationView {
VStack {
if show {
TextField("test", text: $str)
.focused($focus)
}
Button("show & focus") {
show.toggle()
focus.toggle()
}
}
// }
}
}
그런데 여기서 주석을 풀고 VStack 을 NavigationView 안에 들어가도록 넣으면 focus 가 풀리는 문제가 생긴다. @State 변수 show 가 바뀌고 computed 프로퍼티인 body 가 다시 그려지면서 NavigationView 가 focus 를 빼앗는 게 아닌가 하는 추측을 하고 있다.
NavigationView 를 안 쓰면 그만이지만 앱 NavigationView 안에서 NavigationLink 를 쓰고 있어서 NavigationView 를 버릴 수 없었다. 그래서 Opacity 를 써 버렸다. if 는 뷰가 없는 상태에서 appear 되는 것이지만 opacity 는 눈에만 안보이고 사실은 뷰가 있는 상태이다. 이렇게 하면 NavigationView 안에 있어도 focus 가 풀리지 않는다.
import SwiftUI
struct ContentView: View {
@State private var str = ""
@State private var show = false
@FocusState private var focus: Bool
var body: some View {
NavigationView {
VStack {
TextField("test", text: $str)
.focused($focus)
.opacity(show ? 1 : 0)
Button("show & focus") {
show.toggle()
focus.toggle()
}
}
}
}
}
텍스트 필드가 포커스 되어 있는가 상태를 체크하기 위해 @FocusState 대신 iOS14 이하까지 쓰던 UITextFieldDelegate 를 사용할 수도 있긴 하다. 다만 꽤나 번거로운 작업이라 @FocusState 를 자주 쓰는 중이다.