secant-ios-wallet/secant/_Unmodularized/Utils/KeyboardAdaptive.swift

55 lines
1.9 KiB
Swift

//
// KeyboardAdaptive.swift
// KeyboardAvoidanceSwiftUI
//
// Created by Vadim Bulavin on 3/27/20.
// Copyright © 2020 Vadim Bulavin. All rights reserved.
//
import SwiftUI
import Combine
/// Note that the `KeyboardAdaptive` modifier wraps your view in a `GeometryReader`,
/// which attempts to fill all the available space, potentially increasing content view size.
struct KeyboardAdaptive: ViewModifier {
@State private var offsetY: CGFloat = 0
func body(content: Content) -> some View {
GeometryReader { geometry in
withAnimation(.easeOut(duration: 0.16)) {
content
.offset(x: 0, y: self.offsetY)
.onReceive(Publishers.keyboardHeight) { keyboardHeight in
let keyboardTop = geometry.frame(in: .global).height - keyboardHeight
let focusedTextInputBottom = UIResponder.currentFirstResponder?.globalFrame?.maxY ?? 0
self.offsetY = -(max(0, focusedTextInputBottom - keyboardTop - geometry.safeAreaInsets.bottom))
}
}
}
}
}
extension View {
func keyboardAdaptive() -> some View {
ModifiedContent(content: self, modifier: KeyboardAdaptive())
}
}
extension Publishers {
static var keyboardHeight: AnyPublisher<CGFloat, Never> {
let willShow = NotificationCenter.default.publisher(for: UIApplication.keyboardWillShowNotification)
.map { $0.keyboardHeight }
let willHide = NotificationCenter.default.publisher(for: UIApplication.keyboardWillHideNotification)
.map { _ in CGFloat(0) }
return MergeMany(willShow, willHide)
.eraseToAnyPublisher()
}
}
extension Notification {
var keyboardHeight: CGFloat {
return (userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect)?.height ?? 0
}
}