55 lines
1.9 KiB
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
|
|
}
|
|
}
|