아래의 경우를 keyboard
사용하여 숨기는 방법 SwiftUI
?
사례 1
나는이 TextField
와 나는를 숨길 필요가 keyboard
사용자가 클릭 할 때 return
버튼을 누릅니다.
사례 2
나는이 TextField
와 나는를 숨길 필요가 keyboard
사용자가 외부 탭 때.
어떻게 이것을 사용하여 할 수 SwiftUI
있습니까?
노트 :
에 대해 질문하지 않았습니다 UITextField
. 을 사용하여 수행하고 싶습니다 SwifUI.TextField
.
답변
공유 응용 프로그램에 작업을 전송하여 첫 번째 응답자가 사임하도록 강제 할 수 있습니다.
extension UIApplication {
func endEditing() {
sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
이제이 방법을 사용하여 원할 때마다 키보드를 닫을 수 있습니다.
struct ContentView : View {
@State private var name: String = ""
var body: some View {
VStack {
Text("Hello \(name)")
TextField("Name...", text: self.$name) {
// Called when the user tap the return button
// see `onCommit` on TextField initializer.
UIApplication.shared.endEditing()
}
}
}
}
탭 아웃으로 키보드를 닫으려면 탭 동작으로 전체 화면 흰색보기를 만들 수 있습니다. 그러면 다음이 트리거됩니다 endEditing(_:)
.
struct Background<Content: View>: View {
private var content: Content
init(@ViewBuilder content: @escaping () -> Content) {
self.content = content()
}
var body: some View {
Color.white
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
.overlay(content)
}
}
struct ContentView : View {
@State private var name: String = ""
var body: some View {
Background {
VStack {
Text("Hello \(self.name)")
TextField("Name...", text: self.$name) {
self.endEditing()
}
}
}.onTapGesture {
self.endEditing()
}
}
private func endEditing() {
UIApplication.shared.endEditing()
}
}
답변
많은 시도 끝에 나는 (현재) 어떤 컨트롤도 차단하지 않는 솔루션을 찾았습니다-제스처 인식기를 UIWindow
.
- 드래그를 처리하지 않고 외부 탭에서만 키보드를 닫으려면
UITapGestureRecognizer
3 단계 만 사용하면됩니다 . -
모든 터치에서 작동하는 사용자 정의 제스처 인식기 클래스를 만듭니다.
class AnyGestureRecognizer: UIGestureRecognizer { override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) { if let touchedView = touches.first?.view, touchedView is UIControl { state = .cancelled } else if let touchedView = touches.first?.view as? UITextView, touchedView.isEditable { state = .cancelled } else { state = .began } } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { state = .ended } override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) { state = .cancelled } }
-
에서
SceneDelegate.swift
에서func scene
, 다음 코드를 추가합니다 :let tapGesture = AnyGestureRecognizer(target: window, action:#selector(UIView.endEditing)) tapGesture.requiresExclusiveTouchType = false tapGesture.cancelsTouchesInView = false tapGesture.delegate = self //I don't use window as delegate to minimize possible side effects window?.addGestureRecognizer(tapGesture)
-
UIGestureRecognizerDelegate
동시 터치를 허용하도록 구현 합니다.extension SceneDelegate: UIGestureRecognizerDelegate { func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { return true } }
이제 모든보기의 모든 키보드는 터치시 닫히거나 외부로 드래그됩니다.
추신 : 특정 TextField 만 닫으려면 TextField 콜백이 호출 될 때마다 창에 제스처 인식기를 추가하고 제거하십시오. onEditingChanged
답변
@RyanTCB의 대답은 좋습니다. 다음은 사용을 단순화하고 잠재적 인 충돌을 방지하는 몇 가지 개선 사항입니다.
struct DismissingKeyboard: ViewModifier {
func body(content: Content) -> some View {
content
.onTapGesture {
let keyWindow = UIApplication.shared.connectedScenes
.filter({$0.activationState == .foregroundActive})
.map({$0 as? UIWindowScene})
.compactMap({$0})
.first?.windows
.filter({$0.isKeyWindow}).first
keyWindow?.endEditing(true)
}
}
}
‘버그 수정’은 단순히 keyWindow!.endEditing(true)
적절해야한다는 것입니다 keyWindow?.endEditing(true)
(예, 불가능하다고 주장 할 수 있습니다.)
더 흥미로운 것은 어떻게 사용할 수 있는지입니다. 예를 들어, 편집 가능한 필드가 여러 개인 양식이 있다고 가정합니다. 다음과 같이 포장하십시오.
Form {
.
.
.
}
.modifier(DismissingKeyboard())
이제 키보드가없는 컨트롤을 탭하면 적절한 해제가 수행됩니다.
(베타 7로 테스트)
답변
NavigationView 내에서 TextField를 사용하는 동안 이것을 경험했습니다. 이것이 나의 해결책입니다. 스크롤을 시작할 때 키보드를 닫습니다.
NavigationView {
Form {
Section {
TextField("Receipt amount", text: $receiptAmount)
.keyboardType(.decimalPad)
}
}
}
.gesture(DragGesture().onChanged{_ in UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)})
답변
keyWindow
속성에 액세스 할 필요가없는 키보드를 해제하는 다른 방법을 찾았습니다 . 사실 컴파일러는 다음을 사용하여 경고를 반환합니다.
UIApplication.shared.keyWindow?.endEditing(true)
‘keyWindow’는 iOS 13.0에서 더 이상 사용되지 않음 : 연결된 모든 장면에서 키 창을 반환하므로 여러 장면을 지원하는 응용 프로그램에 사용해서는 안됩니다.
대신 다음 코드를 사용했습니다.
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to:nil, from:nil, for:nil)
답변
‘SceneDelegate.swift’파일의 SwiftUI는 다음을 추가합니다. .onTapGesture {window.endEditing (true)}
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
// Create the SwiftUI view that provides the window contents.
let contentView = ContentView()
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(
rootView: contentView.onTapGesture { window.endEditing(true)}
)
self.window = window
window.makeKeyAndVisible()
}
}
앱에서 키보드를 사용하는 각 뷰에 충분합니다.
답변
SwiftUI 2
다음은 업데이트 된 솔루션입니다. SwiftUI 2 / 아이폰 OS (14) (원래 제안 여기 미하일에 의해).
사용하지 않습니다 AppDelegate
.SceneDelegate
당신이 SwiftUI 라이프 사이클을 사용하는 경우 누락 된을 :
@main
struct TestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onAppear(perform: UIApplication.shared.addTapGestureRecognizer)
}
}
}
extension UIApplication {
func addTapGestureRecognizer() {
guard let window = windows.first else { return }
let tapGesture = UITapGestureRecognizer(target: window, action: #selector(UIView.endEditing))
tapGesture.requiresExclusiveTouchType = false
tapGesture.cancelsTouchesInView = false
tapGesture.delegate = self
window.addGestureRecognizer(tapGesture)
}
}
extension UIApplication: UIGestureRecognizerDelegate {
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true // set to `false` if you don't want to detect tap during other gestures
}
}
다음은 길게 누르기 제스처를 제외한 동시 제스처를 감지하는 방법의 예입니다.
extension UIApplication: UIGestureRecognizerDelegate {
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return !otherGestureRecognizer.isKind(of: UILongPressGestureRecognizer.self)
}
}