📝

modifierでsheetを表示すると、そのsheetにあるTextFieldでfocusedが機能しない

に公開

タイトルの通り

改めて眺めると、sheetに表示するViewを切り出す方が自然な気がしてきた。

import SwiftUI

@main
struct SwiftDataSampleApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView(viewModel: ViewModel())
        }
    }
}
import SwiftUI

class ViewModel: ObservableObject {
    @Published var text1: String = "123"
    @Published var text2: String = "456"
    @Published var showSheet: Bool = false
}

struct ContentView: View {
    @ObservedObject var viewModel: ViewModel
    
    var body: some View {
        VStack {
            Button(action: {
                viewModel.showSheet.toggle()
            }) {
                Text("Open")
            }
        }
        .modifier(SheetModifier(viewModel: self.viewModel))
    }
}

struct SheetModifier: ViewModifier {
    enum Field: Hashable {
        case text1
        case text2
    }

    @ObservedObject var viewModel: ViewModel
    @FocusState var isFocused: Field?

    func body(content: Content) -> some View {
        return content
            .sheet(isPresented: $viewModel.showSheet) {
                VStack {
                    Spacer()

                    GroupBox {
                        VStack {
                            TextField("", text: $viewModel.text1)
                                .focused($isFocused, equals: .text1)
                                .keyboardType(.numbersAndPunctuation)
                                .multilineTextAlignment(.trailing)
                                .textFieldStyle(.roundedBorder)
                            TextField("", text: $viewModel.text2)
                                .focused($isFocused, equals: .text2)
                                .keyboardType(.numbersAndPunctuation)
                                .multilineTextAlignment(.trailing)
                                .textFieldStyle(.roundedBorder)
                        }
                    }
                    .onTapGesture {
                        print("onTapGesture \(isFocused)")
                        // ここでisFocusedにnilを代入してキーボードを閉じたい
                    }

                    Spacer()
                }
                .presentationDetents([.medium])
            }
    }
}

#Preview {
    ContentView(viewModel: ViewModel())
}

というわけで、書き直したら機能した。

import SwiftUI

class ViewModel: ObservableObject {
    @Published var text1: String = "123"
    @Published var text2: String = "456"
    @Published var showSheet: Bool = false
}

struct ContentView: View {
    @ObservedObject var viewModel: ViewModel
    
    var body: some View {
        VStack {
            Button(action: {
                viewModel.showSheet.toggle()
            }) {
                Text("Open")
            }
        }
        .sheet(isPresented: $viewModel.showSheet) {
            SheetView(viewModel: self.viewModel)
                .presentationDetents([.medium])
        }
    }
}

struct SheetView: View {
    enum Field: Hashable {
        case text1
        case text2
    }

    @ObservedObject var viewModel: ViewModel
    @FocusState var isFocused: Field?

    var body: some View {
        VStack {
            Spacer()
            
            GroupBox {
                VStack {
                    TextField("", text: $viewModel.text1)
                        .focused($isFocused, equals: .text1)
                        .keyboardType(.numbersAndPunctuation)
                        .multilineTextAlignment(.trailing)
                        .textFieldStyle(.roundedBorder)
                    TextField("", text: $viewModel.text2)
                        .focused($isFocused, equals: .text2)
                        .keyboardType(.numbersAndPunctuation)
                        .multilineTextAlignment(.trailing)
                        .textFieldStyle(.roundedBorder)
                }
            }
            .onTapGesture {
                print("onTapGesture \(isFocused)")
            }
            
            Spacer()
        }
    }
}

#Preview {
    ContentView(viewModel: ViewModel())
}

Discussion