iOS: 如何停止接收键盘按键后的键盘显示通知?

问题描述 投票:1回答:1

我正在尝试做键盘自适应行为。我已经订阅了 keyboardWillShowNotificationkeyboardWillHideNotification我收到了所有这些事件的预期。但我有一个问题 keyboardWillShowNotification: 我按了键盘的按钮后收到一次。

Example

这是我的监听器的代码。

import SwiftUI
import Combine

// MARK: - View

struct ContentView: View {
    @State private var text: String = ""

    var body: some View {
        VStack{
            Text(text)
            Spacer()
            TextField("Input your text", text: $text)
            .textFieldStyle(RoundedBorderTextFieldStyle())
        }
        .padding()
        .keyboardAdaptive()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

// MARK: - Keyboard hacks

extension Notification {
    var keyboardHeight: CGFloat {
        return (userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect)?.height ?? 0
    }
}

extension Publishers {
    static var keyboardHeight: AnyPublisher<CGFloat, Never> {
        let willShow = NotificationCenter.default.publisher(for: UIApplication.keyboardWillShowNotification)
            .map { (n: Notification) -> CGFloat in
                print("will show")
                return n.keyboardHeight
            }

        let willHide = NotificationCenter.default.publisher(for: UIApplication.keyboardWillHideNotification)
            .map { (n: Notification) -> CGFloat in
                print("will hide")
                return CGFloat(0)
            }

        return MergeMany(willShow, willHide)
            .eraseToAnyPublisher()
    }
}

// MARK: -- Detect focused element
extension UIResponder {
    static var currentFirstResponder: UIResponder? {
        _currentFirstResponder = nil
        UIApplication.shared.sendAction(#selector(UIResponder.findFirstResponder(_:)), to: nil, from: nil, for: nil)
        return _currentFirstResponder
    }

    private static weak var _currentFirstResponder: UIResponder?

    @objc private func findFirstResponder(_ sender: Any) {
        UIResponder._currentFirstResponder = self
    }

    var globalFrame: CGRect? {
        guard let view = self as? UIView else { return nil }
        return view.superview?.convert(view.frame, to: nil)
    }
}

// MARK: -- Keyboard Adaptive Modifier

struct KeyboardAdaptive: ViewModifier {
    @State private var bottomPadding: CGFloat = 0

    func body(content: Content) -> some View {
        GeometryReader { geometry in
            content
                .padding(.bottom, self.bottomPadding)
                .onReceive(Publishers.keyboardHeight) { keyboardHeight in
                    let keyboardTop = geometry.frame(in: .global).height - keyboardHeight
                    let focusedTextInputBottom = UIResponder.currentFirstResponder?.globalFrame?.maxY ?? 0
                    self.bottomPadding = max(0, focusedTextInputBottom - keyboardTop - geometry.safeAreaInsets.bottom)
            }
            .animation(.easeOut(duration: 0.16))
        }
    }
}

extension View {
    func keyboardAdaptive() -> some View {
        ModifiedContent(content: self, modifier: KeyboardAdaptive())
    }
}

I am a new guy in mobile development, can anyone help me with this? 我是一个移动开发的新人,谁能帮帮我?

ios swift swiftui
1个回答
1
投票

最简单的方法是忽略相同的条件,就像下面。用Xcode 11.4 iOS 13.4测试。

demo

struct KeyboardAdaptive: ViewModifier {
    @State private var bottomPadding: CGFloat = 0

    func body(content: Content) -> some View {
        GeometryReader { geometry in
            content
                .padding(.bottom, self.bottomPadding)
                .onReceive(Publishers.keyboardHeight) { keyboardHeight in
                    // Just ignore equal resend
                    if keyboardHeight > 0 && self.bottomPadding > 0 { return }   // << here !!

                    let keyboardTop = geometry.frame(in: .global).height - keyboardHeight
                    let focusedTextInputBottom = UIResponder.currentFirstResponder?.globalFrame?.maxY ?? 0
                    self.bottomPadding = max(0, focusedTextInputBottom - keyboardTop - geometry.safeAreaInsets.bottom)
            }
            .animation(.easeOut(duration: 0.16))
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.