ios - iOS:如何在键盘按键后停止接收keyboardWillShowNotification

标签 ios swift swiftui

我正在尝试进行键盘自适应行为。我已经订阅了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())
    }
}

我是移动开发领域的新手,有人可以帮助我吗?

最佳答案

简单的是忽略相同的条件,如下所示。经过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))
        }
    }
}

关于ios - iOS:如何在键盘按键后停止接收keyboardWillShowNotification,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61381303/

相关文章:

ios - 将矩阵转换为 CGAffineTransform

ios - 在SwiftUI中,应用程序卡住到一半时没有任何警告,但在完成前释放

iOS谷歌VR SDK : Unable to preview Video

ios - 使用 SKActions Objective C 的无尽 Action

ios in app购买总是失败

ios - 基于点的聚类计算热图权重

swift - 如何刷新弹出窗口

swiftui - 如何根据textview内容管理Scrollview Height Swiftui

iphone - 保存从互联网下载的数据

使用闭包回调的ios内存泄漏