Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deal with iOs keyboard overlapping entry when the page already has a scrollview in Xamarin Forms

I am having a problem regarding the keyboard on iOS. I am developing a chat page on Xamarin, cross platform, and this page has a scrollView which make possible to the user to scroll along the messages.

There is a commom problem regarding the keyboard on iOS, where it covers the entry. iOS doesn't scroll up the page automatically. To solve this problem, a simple solution is to put a tag "Scrollview" covering the whole code of the page. This usually works fine. However, my page already has a scrollview inside it. Therefore, when I put a scrollview inside another scrollview, the behaviour is a little crazy, even on Android. Sometimes it scrolls the "messages view", sometimes it scrolls the whole page.

There is a solution to avoid the keyboard problem on iOS not using the scrollview tag? Or there is a solution to use a scrollview inside another scrollview?

Any suggestions?

Thank you in advance!

like image 283
Artur Quirino Avatar asked Jan 10 '17 11:01

Artur Quirino


3 Answers

I encountered the same problem while trying to implement a chat feature in our app. A solution is to use a custom renderer for the Entry, and adjust its margin when the keyboard event is triggered. I followed the pattern set in this post.

In this case, I embed my Entry into a ContentView, so I inherit from a ViewRenderer to adjust the ContentView. Depending on the situation, the Renderer you inherit from may vary. However, in most cases you should be able to reset the margin to the Keyboard's height.

using System;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using HBIClientFacingApp;
using HBIClientFacingApp.iOS;

[assembly:ExportRenderer( typeof(ChatViewWithEntry), typeof(ChatEntryRenderer))]
namespace YourNameSpace.iOS
{
    public class ChatEntryRenderer : ViewRenderer //Depending on your situation, you will need to inherit from a different renderer
    {
        public ChatEntryRenderer()
        {   
            UIKeyboard.Notifications.ObserveWillShow ((sender, args) => {

                if (Element != null)
                {
                    Element.Margin = new Thickness(0,0,0, args.FrameEnd.Height); //push the entry up to keyboard height when keyboard is activated
                }
            });

            UIKeyboard.Notifications.ObserveWillHide ((sender, args) => {

                if (Element != null)
                {
                       Element.Margin = new Thickness(0); //set the margins to zero when keyboard is dismissed
                }

            }); 
        }

    }
}
like image 90
UncaughtException Avatar answered Nov 14 '22 02:11

UncaughtException


One way you can deal with this is a custom page renderer that scrolls the whole page up when the keyboard appears.

Here is some sample code to do this. I assume you would only want to do this on pages that have that need it, so first in the Forms PCL (Portable Class Library) project create an empty subclass of ContentPage e.g. called KeyboardInputContentPage (or whatever you like):

public class KeyboardInputContentPage : ContentPage {}

Then you inherit from the KeyboardInputContentPage for the actual page(s) that you need this functionality, in my test I called it TestKeyboardInputContentPage:

public partial class TestKeyboardInputContentPage : KeyboardInputContentPage
{ 
    public TestKeyboardInputContentPage()
    {
        InitializeComponent();
    }
    //etc
}

And the custom page renderer code. This goes in the iOS app project:

[assembly: ExportRenderer(typeof(KeyboardInputContentPage), typeof(ContentPageRenderer))]
namespace MyAppName.iOS
{
    public class ContentPageRenderer : PageRenderer
    {   
        private NSObject keyBoardWillShow;
        private NSObject keyBoardWillHide;
        private nfloat scrollAmout;
        private double animDuration;
        private UIViewAnimationCurve animCurve;
        private bool keyboardShowing;

        public override void ViewDidLoad()
        {

            base.ViewDidLoad();

            keyBoardWillShow = UIKeyboard.Notifications.ObserveWillShow(KeyboardWillShow);

            keyBoardWillHide = UIKeyboard.Notifications.ObserveWillHide(KeyboardWillHide);
        }

        void KeyboardWillShow(object sender, UIKeyboardEventArgs args)
        {
            if (!keyboardShowing)
            {
                keyboardShowing = true;
                animDuration = args.AnimationDuration;
                animCurve = args.AnimationCurve;

                var r = UIKeyboard.FrameBeginFromNotification(args.Notification);
                scrollAmout = r.Height;
                ScrollTheView(true);
            }
        }

        void KeyboardWillHide(object sender, UIKeyboardEventArgs args)
        {
            if (keyboardShowing)
            {
                keyboardShowing = false;
                animDuration = args.AnimationDuration;
                animCurve = args.AnimationCurve;

                var r = UIKeyboard.FrameBeginFromNotification(args.Notification);
                scrollAmout = r.Height;
                ScrollTheView(false);
            }
        }

        private void ScrollTheView(bool scale)
        {
            UIView.BeginAnimations(string.Empty, IntPtr.Zero);
            UIView.SetAnimationDuration(animDuration);
            UIView.SetAnimationCurve(animCurve);

            var frame = View.Frame;

            if (scale)
                frame.Y -= scrollAmout;
            else
                frame.Y += scrollAmout;
            View.Frame = frame;
            UIView.CommitAnimations();
        }
    }
}

Since this renderer actually scrolls the entire native page up and back down when the keyboard shows and hides, it should not matter how you layout the page in the Forms Xaml. All that matters is that your Forms page inherits from KeyboardInputContentPage.

I hope this helps!

like image 28
jgoldberger - MSFT Avatar answered Nov 14 '22 02:11

jgoldberger - MSFT


For iOS you can use this Plugin (add to your iOS project): https://github.com/paulpatarinski/Xamarin.Forms.Plugins/tree/master/KeyboardOverlap

For Android add following string in MainActivity after LoadApplication(new App());

App.Current.On<Xamarin.Forms.PlatformConfiguration.Android>().
UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize);

// this can also be done by adding WindowSoftInputMode = SoftInput.AdjustResize as shown below:
 [Activity(WindowSoftInputMode = SoftInput.AdjustResize)]
like image 4
ajaysinh rajput Avatar answered Nov 14 '22 01:11

ajaysinh rajput