iOS: как перестать получать клавиатуру WillWhowNotification после нажатия клавиши клавиатуры - PullRequest
1 голос
/ 23 апреля 2020

Я пытаюсь настроить поведение клавиатуры. Я подписался на keyboardWillShowNotification и keyboardWillHideNotification, я получаю все эти события, как и ожидалось. Но у меня проблема с 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())
    }
}

Я новичок в разработке мобильных приложений, кто-нибудь может мне помочь с этим?

1 Ответ

1 голос
/ 23 апреля 2020

Простым является игнорирование того же условия, как показано ниже. Протестировано с 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))
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...