This post presents an implementation of animations that animate alongside the iOS keyboard animation. Following the method in this post will allow your views to animate smoothly when the iOS keyboard shows and hides.
A big thanks to @Erel who provided code to read the UIKeyboardAnimationDurationUserInfoKey when the keyboard opens or closes:
www.b4x.com
I have changed the code from the original post so that you can also read the UIKeyboardAnimationCurveUserInfoKey.
Add this objc code to the end of one of the modules:
This code also adds the "will hide" event (https://www.b4x.com/android/forum/threads/keyboard-will-hide-notification.126640/#content). Note that the KeyboardStateChanged event will be raised twice when the keyboard closes.
This is the code for animating our text field or panel that can be placed directly under the other objc code:
In B4XPage_Created call this:
Read out everything and animate the text field:
Example project is attached.
A big thanks to @Erel who provided code to read the UIKeyboardAnimationDurationUserInfoKey when the keyboard opens or closes:
Get UIKeyboardAnimationDurationUserInfoKey and get UIKeyboardAnimationCurveUserInfoKey
I would like to synchronize the opening of my bottom sheet with a textfield on it, with the opening of the keyboard to create a smoother user experience. I come across tutorials online that read and work with the following 2 objects...

I have changed the code from the original post so that you can also read the UIKeyboardAnimationCurveUserInfoKey.
Add this objc code to the end of one of the modules:
B4X:
#if OBJC
@end
@interface B4IViewController (Keyboard2)
@end
@implementation B4IViewController (Keyboard2)
- (void) addWillHide {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
[self storeAnimationInfo:notification];
[B4IObjectWrapper raiseEvent:self :@"_keyboardstatechanged:" :@[@(keyboardSize.height)]];
}
- (void)storeAnimationInfo:(NSNotification*)notification {
NSDictionary *userInfo = [notification userInfo];
double duration = ((NSNumber*)[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]).doubleValue;
NSInteger curve = ((NSNumber*)[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey]).integerValue;
NSMutableDictionary *map = [B4IObjectWrapper getMap:self];
map[@"animation_duration"] = @(duration);
map[@"animation_curve"] = @(curve);
}
- (void)keyboardDidHide:(NSNotification *)notification {
[self storeAnimationInfo:notification];
[B4IObjectWrapper raiseEvent:self :@"_keyboardstatechanged:" :@[@(0)]];
}
#end if
This is the code for animating our text field or panel that can be placed directly under the other objc code:
B4X:
#if OBJC
@end
@interface B4IViewController (KeyboardAnimator)
@end
@implementation B4IViewController (KeyboardAnimator)
- (void)animateView:(UIView *)view
toYPosition:(CGFloat)y
duration:(double)duration
curve:(NSInteger)curve {
UIViewAnimationCurve animCurve = (UIViewAnimationCurve)curve;
UIViewPropertyAnimator *animator = [[UIViewPropertyAnimator alloc]
initWithDuration:duration
curve:animCurve
animations:^{
CGRect frame = view.frame;
frame.origin.y = y;
view.frame = frame;
[self.view layoutIfNeeded];
}];
[animator startAnimation];
}
#end if
In B4XPage_Created call this:
B4X:
#if B4i
Dim no As NativeObject = B4XPages.GetNativeParent(Me) 'or Page1 in non-B4XPages project.
no.RunMethod("addWillHide", Null)
#End If
Read out everything and animate the text field:
B4X:
Private Sub B4XPage_KeyboardStateChanged (Height As Float)
m_KeyboardHeight = Height
Dim ow As NativeObject
Dim duration As Int = ow.Initialize("B4IObjectWrapper").RunMethod("getMap:", Array(B4XPages.GetNativeParent(Me))) _
.RunMethod("objectForKey:", Array("animation_duration")).AsNumber * 1000
Log("duration in ms: " & duration)
Log("keyboard state changed: " & Height)
Dim curveIndex As Int = ow.Initialize("B4IObjectWrapper").RunMethod("getMap:", Array(B4XPages.GetNativeParent(Me))) _
.RunMethod("objectForKey:", Array("animation_curve")).AsNumber
Log("curve: " & curveIndex)
Dim Page As NativeObject = B4XPages.GetNativeParent(Me)
If Height > 0 Then 'Keyboard is open
xpnl_AddNewGroup.Top = Root.Height - xpnl_AddNewGroup.Height
Page.RunMethod("animateView:toYPosition:duration:curve:", Array(xpnl_AddNewGroup, Root.Top + Root.Height - Height - xpnl_AddNewGroup.Height, duration, curveIndex))
Else 'Keyboard is closed
Page.RunMethod("animateView:toYPosition:duration:curve:", Array(xpnl_AddNewGroup,Root.Height - xpnl_AddNewGroup.Height - B4XPages.GetNativeParent(Me).SafeAreaInsets.Bottom, duration, curveIndex))
End If
End Sub
Example project is attached.