This document describes the keyboard avoidance implementation for the Messenger iOS app, ensuring that the ChatInputView is not overlapped by the keyboard on iOS 16+ (including iOS 16.0.1 and 16.1).
The SwiftUI-based ChatInputView was not properly avoiding the keyboard when it appeared, potentially causing the input field to be hidden behind the keyboard.
A custom ViewModifier that listens to keyboard notifications and adds appropriate bottom padding.
Location: Sources/C24ProfisNativeMessenger/Shared/Modifier/KeyboardAdaptiveModifier.swift
How it works:
- Subscribes to
Publishers.keyboardHeight(already available in the codebase) - Calculates keyboard height minus safe area insets to avoid double-counting
- Adds dynamic bottom padding with smooth animation
- Uses
GeometryReaderin background to avoid layout interference
.keyboardAdaptive()The modifier is applied to the main VStack in MainView.swift at line 86:
VStack(spacing: 0) {
// ... message list and attachments ...
ChatInputView(viewModel: viewModel)
}
.keyboardAdaptive() // ← Applied here
.background(viewModel.config.lookAndFeel.backgroundColor.color)The ChatInputView maintains .ignoresSafeArea(edges: .bottom) on its background color (line 33) to ensure the background extends all the way to the bottom of the screen, while the content itself respects the keyboard padding from the parent.
- ✅ Uses keyboard notifications with proper safe area calculations
- ✅ Smooth animations (0.25s ease-out)
- ✅ Automatic keyboard dismissal on scroll (via
dismissKeyboardOnScrollCompat())
- ✅ Full backward compatibility
- ✅ Uses same keyboard notification system
Test on the following iOS versions:
- iOS 15.0
- iOS 16.0
- iOS 16.0.1
- iOS 16.1
- iOS 17.0+
- iOS 18.0+
Test scenarios:
- Tap on text input field - keyboard appears, input visible
- Type long message - input expands, remains visible
- Rotate device with keyboard open
- Switch between apps with keyboard open
- Test on devices with and without home button (different safe areas)
- Test in landscape orientation
- Scroll message list - keyboard dismisses interactively
- KeyboardAdaptiveModifier.swift - Main keyboard avoidance logic
- MainView.swift - Application point (line 86)
- ChatInputView.swift - Input view with background handling (line 33)
- Publisher+Extensions.swift -
Publishers.keyboardHeightpublisher (lines 54-66) - ScrollDownDismissKeyboardModifier.swift - Keyboard dismissal on scroll
- Keyboard.swift - Utility for programmatic keyboard dismissal
SwiftUI has built-in keyboard avoidance, but it can be inconsistent, especially with:
- Complex view hierarchies
- Custom safe area modifications
- Background views that ignore safe areas
The legacy MessengerViewController.swift uses UIKit-based keyboard handling:
stackView.directionalLayoutMargins.bottom = keyboardViewEndFrame.height - view.safeAreaInsets.bottomThe SwiftUI approach mirrors this logic but in a declarative way.
Issue: Input still hidden by keyboard
Possible causes:
- Safe area calculation incorrect - check device safe area insets
- Multiple
.ignoresSafeArea()modifiers conflicting - View hierarchy changed
Solution: Verify .keyboardAdaptive() is on the correct parent view
Possible causes:
- Safe area being counted twice
- Custom padding added elsewhere
Solution: Check geometry.safeAreaInsets.bottom calculation in modifier
Possible causes:
- Other animations interfering
- Animation duration mismatch
Solution: Adjust animation parameters in KeyboardAdaptiveModifier (line 15)
- Keyboard notifications are infrequent (only on keyboard show/hide)
GeometryReaderin background has minimal performance impact- Animation is hardware-accelerated by SwiftUI
- Consider iOS 17+ keyboard layout guide APIs
- Add support for external keyboard detection
- Optimize for iPad split-screen scenarios
- Add haptic feedback on keyboard appearance (if desired)