WindowSoftInputModeAdjust.Resize and Pan on iOS
See original GitHub issueDescription
It would be really great to have Property of ContentPage that enables a similar behaviour to WindowSoftInputModeAdjust.Resize and WindowSoftInputModeAdjust.Pan on Android for iOS.
I think this would be possible by listening to the keyboard up event on iOS. There are a few tutorials showing this for Xamarin.Forms. This would be useful for any page with Entries or Editors.
Moreover, I can’t really think of any scenario where anyone wants their content to be hidden by the keyboard on iOS.
When Pan is chosen, the ContentPage should move up entirely, when Resize is chosen the bottom Padding of the Page could be changed. I have created a example. The animation of the keyboard up event could probably be improved (and should be added for the Resize mode), but I could not find an exact function of the iOS keyboard animation and the animation for padding could probably imitated if first the page is translated up and then afterwards the Translation is removed and Padding set.
This code would probably create some issues, if the ResizeMode is set for the whole App on Android and it might not work correctly when the Resize property is updated on runtime. However, this could be a good starting point and works fine in the scenarios I have tested.
Here is my code:
public partial class KeyboardContentPage : ContentPage
{
public static readonly BindableProperty ResizeProperty = BindableProperty.Create(nameof(Resize), typeof(bool), typeof(KeyboardContentPage), null);
public bool Resize
{
get => (bool)GetValue(ResizeProperty);
set => SetValue(ResizeProperty, value);
}
}
on Android:
public partial class KeyboardContentPage : ContentPage
{
public KeyboardContentPage()
{
if (Resize)
{
App.Current.On<Microsoft.Maui.Controls.PlatformConfiguration.Android>().UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize);
}
else
{
App.Current.On<Microsoft.Maui.Controls.PlatformConfiguration.Android>().UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Pan);
}
}
}
on iOS
public partial class KeyboardContentPage : ContentPage
{
NSObject _keyboardShowObserver;
NSObject _keyboardHideObserver;
public KeyboardContentPage()
{
RegisterForKeyboardNotifications();
}
~KeyboardContentPage()
{
UnregisterForKeyboardNotifications();
}
private Thickness padding;
private double? translationY;
private bool lastAnimationType;
async void OnKeyboardShow(object sender, UIKeyboardEventArgs args)
{
NSValue result = (NSValue)args.Notification.UserInfo.ObjectForKey(new NSString(UIKeyboard.FrameEndUserInfoKey));
CGSize keyboardSize = result.RectangleFValue.Size;
Easing anim = Easing.SpringIn;
NFloat bottom;
try
{
UIWindow window = UIApplication.SharedApplication.Delegate.GetWindow();
bottom = window.SafeAreaInsets.Bottom;
}
catch
{
bottom = 0;
}
var heightChange = (keyboardSize.Height - bottom);
lastAnimationType = Resize;
if (Resize)
{
padding = this.Padding;
this.Padding = new Thickness(padding.Left, padding.Top, padding.Right, padding.Bottom + heightChange);
}
else
{
var duration = (uint)(args.AnimationDuration * 1000);
translationY = this.Content.TranslationY;
await this.Content.TranslateTo(0, translationY.Value - heightChange, duration, anim);
}
}
async void OnKeyboardHide(object sender, UIKeyboardEventArgs args)
{
if (lastAnimationType)
{
this.Padding = padding;
}
else
{
Easing anim = Easing.CubicIn;
if (this != null && translationY != null)
{
var duration = (uint)(args.AnimationDuration * 1000);
await this.Content.TranslateTo(0, translationY.Value, duration, anim);
}
}
}
void RegisterForKeyboardNotifications()
{
if (_keyboardShowObserver == null)
_keyboardShowObserver = UIKeyboard.Notifications.ObserveWillShow(OnKeyboardShow);
if (_keyboardHideObserver == null)
_keyboardHideObserver = UIKeyboard.Notifications.ObserveWillHide(OnKeyboardHide);
}
void UnregisterForKeyboardNotifications()
{
if (_keyboardShowObserver != null)
{
_keyboardShowObserver.Dispose();
_keyboardShowObserver = null;
}
if (_keyboardHideObserver != null)
{
_keyboardHideObserver.Dispose();
_keyboardHideObserver = null;
}
}
}
Public API Changes
a new Property called ‘Resize’ on ContentPage. Maybe instead of a bool it would make sense to use an enum called ‘ResizeMode’, with ‘Pan’, ‘Resize’ and ‘None’ instead, where ‘None’ leaves the current behaviour (so the keyboard will hide elements on the bootom of the page on iOS).
Intended Use-Case
Move your content up like on Android on any page that uses Keyboards on iOS!
Just set your desired Mode in Xaml ContenPage like this:
<custom:KeyboardContentPage Resize="True" ..... >
Issue Analytics
- State:
- Created a year ago
- Comments:12

Top Related StackOverflow Question
@angelru Here is my code. At the moment I only use it in a chat window where the entry is below a collectionview. I can only say it works there. If the entry is within the collectionview or within a scrollview, it may need to be adjusted. However, it shows how to use the height change event of the keyboard.
Many thanks to @borrmann! I was (eventually!) able to come up with a workaround for my app.
Here’s the code I’m using: https://gist.github.com/greg84/0297569ef1052801a384aae9c75800cd
Some comments:
Shell.Current.HeightandContentView.Height).ios:Page.UseSafeAreaand others don’t, which affects whether the top safe area inset needs to be considered as part of the content height.