Reputation: 1007
So I have read mutliple articles regarding this issue, but none worked for my case.
What happens:
When you toggle the keyboard by clicking an entry, on Android the whole layout is shifted up by as much as the keyboard is big. iOS simply renderes the keyboard on top. This is ofc terrible, and especially for the chat application I am building right now completely hiding the entry editor field where the user types on. Inacceptable.
There are some solutions (allthoug I really wonder why such a basic thing isnt included into xamarin.ios already)
1.) Putting your layout into a scrollview.
This works. Simply wrap everything into a scrollview, and the keyboard will push everything up. Great, right?
No. In some instances you cannot wrap things into a scrollview: My chat is one example. Since the chat view is a scrollview itself, the outter layers cannot be a scrollview. I mean, they can: but then you have two scrollviews on top of each other leading to scroll issues and both interfering with one another. ALSO: values like height="180"
dont work inside a scrollview anymore because the height isnt a fixed value.
2) Using a plugin
There are many nuget plugins that should work but with the newest iOS they just dont anymore. Some still do, but on few occasions (when the enter button is pressed to disable keyboard) the layout doesnt scroll back down well enough leaving a blank space. So these do not work at all or well enough.
3) Adding a layout that is inflated when the keyboard is triggered
This is what I did as a workaround (that isnt good either):
At the bottom of my layout where my entry field for the chat is I added this layout:
<Grid Grid.Column="1" Grid.Row="2" x:Name="keyboardLayout" IsVisible="false" >
<Grid.RowDefinitions>
<RowDefinition Height="300"/>
</Grid.RowDefinitions>
<BoxView BackgroundColor="Transparent"/>
</Grid>
It is a fixed layout with a height of 300. Now I can listen to keyboard change events:
if (Device.RuntimePlatform == Device.iOS)
{
// Android does it well by itself, iOS is special again
var keyboardService = Xamarin.Forms.DependencyService.Get<IKeyboardService>();
keyboardService.KeyboardIsHidden += delegate
{
keyboardLayout.IsVisible = false;
};
keyboardService.KeyboardIsShown += delegate
{
keyboardLayout.IsVisible = true;
};
}
With a complicated interface (that I am posting if someone wants it), I can listen to change keyboard events. If the keyboard is visible, I simply update the UI with the layout.
This works, but the fixed size of 300 is an issue. To this day I still dont really know how fixed values in XAML work (input wanted...!), for smaller margins they seem to be equal on every phone, but for higher values (> 50) they differ too much.
So my solution is just about good enough for older iPhones (6, 7). But leaves a bit of an empty space between the keyboard and the entry filed on newer iPhones with longer screens (11, 12).
In summary: no solution is ideal.
What we need
Either an important xamarin update facing this issue (which wont happen anytime soon), or someone who knows how to get the height of the keyboard in pixels, translate that into XAML values, and fill them in in regards to the phone used. Then my solution (number 3) would work always, everywhere (still a workaround, but bulletproof).
Is there anybody out there, who knows how to
a.) get the height of the shown keyboard in pixels
and (and most important)
b.) konws how to translate pixels into Height="xxx"
Thank you for comming to my ted talk ;)
Upvotes: 3
Views: 1438
Reputation: 10346
You can create class that extend grid in shared code firstly.
public class KeyboardView: Grid{}
Then create a custom renderer to do the resize control.
[assembly: ExportRenderer(typeof(KeyboardView), typeof(KeyboardViewRenderer))]
namespace KeyboardSample.iOS.Renderers
{
public class KeyboardViewRenderer : ViewRenderer
{
NSObject _keyboardShowObserver;
NSObject _keyboardHideObserver;
protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
RegisterForKeyboardNotifications();
}
if (e.OldElement != null)
{
UnregisterForKeyboardNotifications();
}
}
void RegisterForKeyboardNotifications()
{
if (_keyboardShowObserver == null)
_keyboardShowObserver = UIKeyboard.Notifications.ObserveWillShow(OnKeyboardShow);
if (_keyboardHideObserver == null)
_keyboardHideObserver = UIKeyboard.Notifications.ObserveWillHide(OnKeyboardHide);
}
void OnKeyboardShow(object sender, UIKeyboardEventArgs args)
{
NSValue result = (NSValue)args.Notification.UserInfo.ObjectForKey(new NSString(UIKeyboard.FrameEndUserInfoKey));
CGSize keyboardSize = result.RectangleFValue.Size;
if (Element != null)
{
Element.Margin = new Thickness(0, 0, 0, keyboardSize.Height); //push the entry up to keyboard height when keyboard is activated
}
}
void OnKeyboardHide(object sender, UIKeyboardEventArgs args)
{
if (Element != null)
{
Element.Margin = new Thickness(0); //set the margins to zero when keyboard is dismissed
}
}
void UnregisterForKeyboardNotifications()
{
if (_keyboardShowObserver != null)
{
_keyboardShowObserver.Dispose();
_keyboardShowObserver = null;
}
if (_keyboardHideObserver != null)
{
_keyboardHideObserver.Dispose();
_keyboardHideObserver = null;
}
}
}
}
Finally, adding content inside KeyboardView.
You can take a look this thread:
Upvotes: 1
Reputation: 277
Install Xamarin.IQKeyboardManager nuget package in Xamarin.Forms iOS project only.
Add below code in AppDelegate.cs before Forms.init()
IQKeyboardManager.SharedManager.Enable = true;
IQKeyboardManager.SharedManager.KeyboardDistanceFromTextField = 20;
When you click on entry, it will shift UI up as you mentioned in your question for Android.
Upvotes: 0