WindowSoftInputMode doesn't work in Xamarin Forms Android

YaroslavTsapivYaroslavTsapiv Yaroslav TsapivUSMember

I work with XamarinForms and has some issues with Entry in ScrollView on Android platform. Autoscroll doesn't work correctly when I focuse on an entry placed in ScrollView. Entry appears above the keyboard but the whole page becomes unscrollable (I can't scroll completely to bottom or top of page). I try to set WindowSoftInputMode to adjustPan or adjustResize or both, and I try different ways to set it (in code, by attribute, directly in AndroidManifest.xml). But any case doesn't work (in each cases behavior remain the same). Please, maybe someone have encountered the same problem and I hope can help me. Thanks a lot.

Answers

  • JohnMillerJohnMiller John Miller USForum Administrator, Xamarin Team Xamurai

    @YaroslavTsapiv,

    ScrollView has no affect on Android for scrolling when the keyboard is present. Instead, you will want to set the following in your MainActivity.OnCreate.

    Window.SetSoftInputMode(Android.Views.SoftInput.AdjustResize);
    

    There might be additional problems because of an Android bug. I found a solution to that on Adam Pedleys site.

    public class AndroidBug5497WorkaroundForXamarinAndroid
    {
    
        // For more information, see https://code.google.com/p/android/issues/detail?id=5497
        // To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
    
        // CREDIT TO Joseph Johnson (http://stackoverflow.com/users/341631/joseph-johnson) for publishing the original Android solution on stackoverflow.com
    
        public static void assistActivity(Activity activity)
        {
            new AndroidBug5497WorkaroundForXamarinAndroid(activity);
        }
    
        private Android.Views.View mChildOfContent;
        private int usableHeightPrevious;
        private FrameLayout.LayoutParams frameLayoutParams;
    
        private AndroidBug5497WorkaroundForXamarinAndroid(Activity activity)
        {
            FrameLayout content = (FrameLayout)activity.FindViewById(Android.Resource.Id.Content);
            mChildOfContent = content.GetChildAt(0);
            ViewTreeObserver vto = mChildOfContent.ViewTreeObserver;
            vto.GlobalLayout += (object sender, EventArgs e) => {
                                 possiblyResizeChildOfContent();
                                 };
            frameLayoutParams = (FrameLayout.LayoutParams)mChildOfContent.LayoutParameters;
        }
    
        private void possiblyResizeChildOfContent()
        {
            int usableHeightNow = computeUsableHeight();
            if (usableHeightNow != usableHeightPrevious)
            {
                int usableHeightSansKeyboard = mChildOfContent.RootView.Height;
                int heightDifference = usableHeightSansKeyboard - usableHeightNow;
    
                frameLayoutParams.Height = usableHeightSansKeyboard - heightDifference;
    
                mChildOfContent.RequestLayout();
                usableHeightPrevious = usableHeightNow;
            }
        }
    
        private int computeUsableHeight()
        {
            Rect r = new Rect();
            mChildOfContent.GetWindowVisibleDisplayFrame(r);
            if (Build.VERSION.SdkInt < BuildVersionCodes.Lollipop)
            {
                return (r.Bottom - r.Top);
            }
            return r.Bottom;
        }
    }
    

    Use it after the SetSoftInputMode line:

    AndroidBug5497WorkaroundForXamarinAndroid.assistActivity(this);
    

    The site from the link above also has an example renderer to disable the full screen behavior in landscape.

  • YaroslavTsapivYaroslavTsapiv Yaroslav Tsapiv USMember

    Hi @JohnMiller , thank you for answer. I have tried this solution before. And it doesn't work correctly with ScrollView in my case.
    I have to use ScrollView, because I have a lot of dynamic data in the page. Although this solution works well in Samsung device, but not LG.
    However when I override method RequestChildFocus for ScrollViewRenderer and do not call base.RequestChildFocus the bug goes away, but appears issue with numeric Entry (it stops working). So this solution doesn't solve my issue. I know that this problem can be solved in native Android by WindowSoftInputMode .
    Maybe you know some another solution which will work with scrollView.

  • JohnMillerJohnMiller John Miller USForum Administrator, Xamarin Team Xamurai

    @YaroslavTsapiv,

    Sorry that didn't help! If you have a sample or project you can share that could demostrate the issue you are having on a specific device, please add a bug report on Bugzilla and attach it. Feel free to ping me with the bug number and I will take a look at the project. Please follow the bug writing guidelines when reporting an issue.

  • AlexanderSheetyAlexanderSheety Alexander Sheety RUMember ✭✭

    @JohnMiller

    UWP has the same problem !

    Do you have any solutions for UWP ?

  • JohnMillerJohnMiller John Miller USForum Administrator, Xamarin Team Xamurai

    @AlexanderSheety,

    Yep! There is a solution in the link I posted in my comment.

  • AlexanderSheetyAlexanderSheety Alexander Sheety RUMember ✭✭

    @JohnMiller

    My investigations at Android:
    This solution doesn't work if entry is inside scrollview! View doesn't resize correctly!
    I tested StackLayout,AbsoluteLayout as topmost page layout. I hadn't results!
    But i finded some interesting in Grid. Entry inside scrollview works if Grid is topmost page layout!
    I don't know why only grid, but it is worked!

    Work Sample:

    >! using Xamarin.Forms.PlatformConfiguration;
    >! using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
    >! 
    >! public class App : Xamarin.Forms.Application
    >! {
    >! public App()
    >! {
    >!           this.On<Android>().UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize);
    >!          var stack = new Grid
    >!           {
    >!                   HorizontalOptions = LayoutOptions.FillAndExpand,
    >!                   VerticalOptions = LayoutOptions.FillAndExpand,
    >!                   RowDefinitions =
    >!                   {
    >!                           new RowDefinition { Height = 62 },
    >!                           new RowDefinition { Height = new GridLength(1, GridUnitType.Star) },
    >!                    },     
    >!            };
    >!       var boxmenu=new BoxView{
    >!           BackgroundColor = Color.Black;
    >!           HorizontalOptions = LayoutOptions.FillAndExpand;
    >!                   VerticalOptions = LayoutOptions.FillAndExpand;
    >!       };
    >!       var topmenubar=new AbsoluteLayout{
    >!           HorizontalOptions = LayoutOptions.FillAndExpand;
    >!                   VerticalOptions = LayoutOptions.FillAndExpand;
    >!                   Children={
    >!               {boxmenu, new Rectangle(0, 0, 1, 1), AbsoluteLayoutFlags.All},
    >!       }
    >!       };
    >!       stack.Children.Add(topmenubar,0,0);
    >!  
    >!       var scrollstack=new StackLayout{
    >!           HorizontalOptions = LayoutOptions.FillAndExpand;
    >!                   VerticalOptions = LayoutOptions.Start;
    >!                   BackgroundColor = Color.White;
    >!                   Spacing = 0;
    >!                   Padding = new Thickness(10,0,10,10);
    >!       };
    >!       for (int i=0;i<10;i++)
    >!       {
    >!           var label = new Label {
    >!                       FontSize=15,
    >!                       Text ="Label"+i,
    >!                       TextColor = Color.Black,
    >!                       HorizontalOptions = LayoutOptions.Start,
    >!                       VerticalOptions = LayoutOptions.Start,
    >!               Margin= new Thickness(0,10,0,0);
    >!           };
    >!           var entry = new Entry {
    >!               HorizontalOptions = LayoutOptions.Start,
    >!                       VerticalOptions = LayoutOptions.Start,
    >!                       BackgroundrColor=Color.FromRgb(240,240,240),
    >!                       TextColor=Color.Black,
    >!                       FontSize= 15,
    >!               };
    
    >!           scrollstack.Children.Add(label);
    >!           scrollstack.Children.Add(entry);
    >!            };
    >!       var scroll=new ScrollView{
    >!           Content=scrollstack,
    >!       };
    >!           stack.Children.Add(scroll,0,1);
    >!           MainPage = stack;
    >! }
    >! protected override void OnStart()
    >! {
    >!       // Handle when your app starts
    >! }
    >!  
    >! protected override void OnSleep()
    >! {
    >!       // Handle when your app sleeps
    >! }
    >!  
    >! protected override void OnResume()
    >! {
    >!       // Handle when your app resumes
    >! }
    >! }
    

    My investigations at UWP:
    This solution doesn't work if entry is inside scrollview! View doesn't resize correctly!

    Questions (Android and UWP ):

    1. How can i stop resize or pan view after showing keyboard ?
    2. How can i get keyboard height for calculations scroll height? ( I want to send scroll event to my scrollview )
  • Shane000Shane000 Shane Pope USMember ✭✭✭
    edited June 21
  • ChrisHanChrisHan Christian Hanusch USMember
    edited July 13

    @JohnMiller: Workaround works fine, thanks! I chose the alternative method on Adams site, it is shorter and does not require creating another class.

Sign In or Register to comment.