Настройка вида появления / исчезновения клавиатуры: проблема с кривой анимации - PullRequest
0 голосов
/ 04 апреля 2020

Я пытаюсь создать модификатор представления SwiftUI, который добавляет нижний отступ в ответ на появление или исчезновение экранной клавиатуры. Я использую этот подход:

struct KeyboardAdjustingModifier: ViewModifier {
    @ObservedObject private var responder = KeyboardResponder()

    func body(content: Content) -> some View {
        GeometryReader { proxy in
            content
                .padding(.bottom, self.bottomPadding(in: proxy))
        }
    }

    func bottomPadding(in proxy: GeometryProxy) -> CGFloat {
        if responder.endFrame == .zero {
            return 0
        } else {
            return max(0, proxy.frame(in: .global).maxY - self.responder.endFrame.minY)
        }
    }
}

fileprivate final class KeyboardResponder: ObservableObject {
    @Published var endFrame: CGRect = .zero

    init(notificationCenter: NotificationCenter = .default) {
        notificationCenter.addObserver(self,
                                       selector: #selector(keyboardWillShowOrChangeFrame(notification:)),
                                       name: UIResponder.keyboardWillShowNotification, object: nil)
        notificationCenter.addObserver(self,
                                       selector: #selector(keyboardWillShowOrChangeFrame(notification:)),
                                       name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
        notificationCenter.addObserver(self,
                                       selector: #selector(keyboardWillHide(notification:)),
                                       name: UIResponder.keyboardWillHideNotification, object: nil)
    }

    @objc private func keyboardWillShowOrChangeFrame(notification: Notification) {
        withAnimation(Animation(curve: notification.animationCurve, duration: notification.duration)) {
            endFrame = notification.endFrame
        }
    }

    @objc private func keyboardWillHide(notification: Notification) {
        withAnimation(Animation(curve: notification.animationCurve, duration: notification.duration)) {
            endFrame = .zero
        }
    }

    struct Info {
        let curve: UIView.AnimationCurve
        let duration: TimeInterval
        let endFrame: CGRect
    }
}

fileprivate extension Animation {
    init(curve: UIView.AnimationCurve, duration: TimeInterval) {
        switch curve {
        case .easeInOut:
            self = .easeInOut(duration: duration)
        case .easeIn:
            self = .easeIn(duration: duration)
        case .easeOut:
            self = .easeOut(duration: duration)
        case .linear:
            self = .linear(duration: duration)
        @unknown default:
            self = .easeInOut(duration: duration)
        }
    }
}

fileprivate extension Notification {
    var animationCurve: UIView.AnimationCurve {
        guard let rawValue = (userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? Int) else {
            return UIView.AnimationCurve.linear
        }

        return UIView.AnimationCurve(rawValue: rawValue)!
    }

    var duration: TimeInterval {
        userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval ?? 0
    }

    var endFrame: CGRect {
        userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect ?? .zero
    }
}

Проблема, с которой я сталкиваюсь, заключается в том, что кажется, что кривая анимации SwiftUI весьма отличается от кривой анимации клавиатуры:

Animation curve mismatch

Кто-нибудь знает, возможно ли синхронизировать c анимацию SwiftUI с UIKit, как это? Вполне возможно, что ошибка в том, как я отображаю информацию кривой анимации из уведомления userInfo в кривую анимации SwiftUI. Или есть другой подход к этой проблеме, который я должен рассмотреть?

Еще одна вещь, которую я попробовал, - это использование UIHostingController, который обрабатывает анимацию непосредственно в UIKit. Он правильно синхронизировался с клавиатурой, но у меня возникали сбои при вызове layoutIfNeeded в моих блоках анимации, если SwiftUI также одновременно анимировал материал.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...