Last active
October 2, 2024 07:24
-
-
Save ryanlintott/b57b975c8d2e3cad0353a6b6e9d49928 to your computer and use it in GitHub Desktop.
A SwiftUI environment value for the keyboard height that updates with animation. This is useful when you want a specific view in a stack to stick to the bottom of the keyboard when the keyboard moves up. Now included in FrameUp https://github.com/ryanlintott/FrameUp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
struct ContentView: View { | |
var body: some View { | |
KeyboardAvoidingWithOffset() | |
.keyboardHeightEnvironmentValue() | |
} | |
} | |
struct KeyboardAvoidingWithOffset: View { | |
@Environment(\.keyboardHeight) var keyboardHeight | |
@State private var text = "" | |
var body: some View { | |
VStack { | |
TextField("Hello World", text: $text) | |
.textFieldStyle(.roundedBorder) | |
Color.blue.opacity(0.5) | |
.frame(height: keyboardHeight > 0 ? keyboardHeight : 100) | |
} | |
.frame(maxHeight: .infinity, alignment: .bottom) | |
.ignoresSafeArea(.keyboard) | |
} | |
} | |
#Preview { | |
ContentView() | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// KeyboardHeightEnvironmentValue.swift | |
// KeyboardAvoidance | |
// | |
// Created by Ryan Lintott on 2024-02-01. | |
// | |
import SwiftUI | |
private struct KeyboardHeightEnvironmentKey: EnvironmentKey { | |
static let defaultValue: CGFloat = 0 | |
} | |
extension EnvironmentValues { | |
/// Height of software keyboard when visible | |
var keyboardHeight: CGFloat { | |
get { self[KeyboardHeightEnvironmentKey.self] } | |
set { self[KeyboardHeightEnvironmentKey.self] = newValue } | |
} | |
} | |
struct KeyboardHeightEnvironmentValue: ViewModifier { | |
@State private var keyboardHeight: CGFloat = 0 | |
func body(content: Content) -> some View { | |
content | |
.environment(\.keyboardHeight, keyboardHeight) | |
/// Approximation of Apple's keyboard animation | |
/// source: https://forums.developer.apple.com/forums/thread/48088 | |
.animation(.interpolatingSpring(mass: 3, stiffness: 1000, damping: 500, initialVelocity: 0), value: keyboardHeight) | |
.background { | |
GeometryReader { keyboardProxy in | |
GeometryReader { proxy in | |
Color.clear | |
.onChange(of: keyboardProxy.safeAreaInsets.bottom - proxy.safeAreaInsets.bottom) { newValue in | |
DispatchQueue.main.async { | |
if keyboardHeight != newValue { | |
keyboardHeight = newValue | |
} | |
} | |
} | |
} | |
.ignoresSafeArea(.keyboard) | |
} | |
} | |
} | |
} | |
public extension View { | |
/// Adds an environment value for software keyboard height when visible | |
/// | |
/// Must be applied on a view taller than the keyboard that touches the bottom edge of the safe area. | |
/// Access keyboard height in any child view with | |
/// @Environment(\.keyboardHeight) var keyboardHeight | |
func keyboardHeightEnvironmentValue() -> some View { | |
#if os(iOS) | |
modifier(KeyboardHeightEnvironmentValue()) | |
#else | |
environment(\.keyboardHeight, 0) | |
#endif | |
} | |
} | |
#Preview { | |
VStack { | |
TextField("Example", text: .constant("")) | |
} | |
.keyboardHeightEnvironmentValue() | |
} |
Glad I could help! This code is actually included in my FrameUp package now as well if you're interested.
https://github.com/ryanlintott/FrameUp?tab=readme-ov-file#keyboardHeight
Good!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thinks! You really helped me out of a jam. 😭