dotnet / MobileBlazorBindings

Experimental Mobile Blazor Bindings - Build native and hybrid mobile apps with Blazor
MIT License
1.2k stars 171 forks source link

Virtual keyboard goes on top of input without option of scrolling #222

Open arivera12 opened 3 years ago

arivera12 commented 3 years ago

I am able to scroll the page on regular browser but on BlazorWebView is not possible.

Screenshot_20201106-234922

Eilon commented 3 years ago

On Android you can collapse the keyboard by pressing the Back button or usually there's some other keyboard-close action you can take. But I think I've seen this before and it's quite annoying. I haven't looked into how to fix it but I'm sure there must be a way.

arivera12 commented 3 years ago

Yup it quite annoying, pressing the back button collapse the keyboard but once you focus an input it gets on top of the input again, this need to be workarounded somehow, its makes a form navigation and entry quite imposible, not sure how ios behaves on this one...

Eilon commented 3 years ago

Oh so in this case you want the input to be focused but the keyboard is hiding it? So ideally the input would "scroll up" a bit at least temporarily?

arivera12 commented 3 years ago

Having scrolling capabilities can be considered a fix, but the way this should work is once I focus an input, keyboard should position below the working/focused input.

arivera12 commented 3 years ago

In that screenshot I shared page has no scrolling capabilities, on regular mobile browser it has scrolling capabilities so we should behave like regular mobile browsers do.

arivera12 commented 3 years ago

Oh so in this case you want the input to be focused but the keyboard is hiding it? So ideally the input would "scroll up" a bit at least temporarily?

Yes, is hiding it and is on top of it without scrolling capabilities

arivera12 commented 3 years ago

I think this issue should be considered a bug because it makes any form with no way to fill them without looking the current focused input. I am not able to see the password field on that login form when it's focused...

Eilon commented 3 years ago

Yeah I agree it's a bug I'm just not sure where the bug is. Ideally apps shouldn't have to do much to support this because it's an extremely common scenario. But is it an issue in Mobile Blazor Bindings? In Xamarin.Forms? Somewhere else?

arivera12 commented 3 years ago

I think the bug resides MBB on the BlazorWebView component. It's needs to react to any focused input.

arivera12 commented 3 years ago

Hmmm take a look of this... https://www.xamarinhelp.com/accommodate-on-screen-keyboard-xamarin-forms/

Eilon commented 3 years ago

Oh well that looks easy 😄

arivera12 commented 3 years ago

There is a bug with android it's seems...

arivera12 commented 3 years ago

Not sure if the shared link may help or resolves this issues but it's seems to be related somehow.

arivera12 commented 3 years ago

Related

https://forums.xamarin.com/discussion/87176/windowsoftinputmode-doesnt-work-in-xamarin-forms-android

juanjfrancisco commented 3 years ago

Hi. @arivera12 , the way I fixed that was adjusting the keyboard size with this code:

Android: On the share project in the App.cs class:

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

It looks like this: image

If you can notice in yellow I add the name space Xamarin.Forms to avoid conflict with Xamarin.Forms.PlatformConfiguration.AndroidSpecific.Application, that because the UseWindowSoftInputModeAdjust is an extension in AndroidSpecific.

iOS: Install package Xam.Plugins.Forms.KeyboardOverlap

Add in AppDelegate inside FinishedLaunching method, the line:

KeyboardOverlapRenderer.Init();

Hope that can help you!!

arivera12 commented 3 years ago

@juanjfrancisco I will give it a try

arivera12 commented 3 years ago

@juanjfrancisco it works partially but after losing the input focus the windows doesn't resize back and leave blank space as show on the screenshot Screenshot_20210120-130532

idylmz commented 3 years ago

Before adding new issue, looked for similar bugs and I found this.

I am also experiencing the same issue and when I tried the soft input mode adjust, The screen did not resize back as @arivera12 specified above.

Will there be a fix to this in the near future? Is there any workaround that we can use by the time we have the absolute solution?

Eilon commented 3 years ago

Hi folks, it's not clear to me if there's anything that Mobile Blazor Bindings needs to do or if it's a more general Xamarin/Xamarin.Forms thing, or if it's just a general Android (or other platform) thing. Does anyone know if it's specific to Mobile Blazor Bindings, or would this exact issue happen in any other Xamarin.Forms-based application? If it's more general, we should make sure there is an issue in the appropriate repo.

arivera12 commented 3 years ago

@Eilon it's not clear for me also where it resides.

What @juanjfrancisco proposed works but when the keyboard hides I think the BlazorWebView supposes to resizes back an fit the original window size which it doesn't happens and leaves that blank space on the bottom.

And yes it's an android issue I had tested ios and it's ok.

Eilon commented 3 years ago

@arivera12 thank for the info. The BlazorWebView is a bit complex in terms of how it handles interaction with the native WebView but it doesn't have any logic for resizing/moving things. So maybe it should have some logic like that, or maybe there's an issue in Xamarin.Forms and how it handles things.

Do we have any idea whether it's the size of the Xamarin.Forms control, the native Android WebView, or something else? Does this same issue happen in a plain Xamarin.Forms app with a regular WebView?

arivera12 commented 3 years ago

Let me do a quick xamarin.forms app with some inputs and see how it behaves on android.

arivera12 commented 3 years ago

@Eilon

First test without

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

Xamarin.Forms and BlazorWebView behaves exactly, keyboard goes on top of inputs without scrolling option.

Seconds test including

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

On Xamarin.Forms keyboard has scrolling option and resize back once the keyboard hides.

On BlazorWebView keyboard has scrolling option but doesn't resize back leaving that blank space below once the keyboard hides.

arivera12 commented 3 years ago

Note:

I did test under the conditions of native web view control and regular xamarin input controls and blazorwebview.

Slevya commented 3 years ago

@arivera12 @Eilon I found simple solution!

Method Xamarin.Forms.Application.Current.On().UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize); - have bugs on different android devices, and we disabled that function

Solution:

  1. For Example:

    <div style="margin-bottom:@(margin)px">
    <input type="text" @bind="something"  @onfocusin="OnFocusIn" @onfocusout="OnFocusOut" />
    </div>
    @code {
    private double margin;
    private bool makeMargin;
    }
  2. Handle focus input with two methods. Get keyboard height (on android), e.g 280~300 px

    void OnFocusIn(FocusEventArgs e)
    {
        if (Device.RuntimePlatform == Device.Android) // on ios works fine 
        {
            makeMargin = true;
            SetMargin();
        }
    }
    
    void OnFocusOut(FocusEventArgs e)
    {
        if (Device.RuntimePlatform == Device.Android) // on ios works fine 
        {
            makeMargin = false;
            SetMargin();
        }
    }
    
    void SetMargin()
    {
        if (makeMargin)
        {
            margin = 280;
        }
        else
        {
            margin = 0;
        }
        StateHasChanged();
    }
  3. Profit! And you can scroll blazor content when virtual keyboard showing

    But you can get real virtual anrdoid keyboard height, like using DependencyService

Work example: https://stackoverflow.com/a/63492647/15333425

Remark:

IKeyboardHelper keyboardHelper = DependencyService.Get<IKeyboardHelper>(); 
        keyboardHelper.KeyboardHeightChanged.Subscribe(x => margin = Math.Ceiling(x));
        if (margin == 0)
        {
            await Task.Delay(500);
        }

If you want auto scroll when focus input (virtual keboard showing):

  1. Add div with id into blazor view, like focusDiv

    <div style="margin-bottom:@(margin)px">
    <input type="text" @bind="something"  @onfocusin="OnFocusIn" @onfocusout="OnFocusOut" />
    </div>
    <div id="focusDiv"></div>
  2. Change OnFocusIn method name to OnFocusInAsync, add some delay and invoke js function

    async Task OnFocusInAsync(FocusEventArgs e)
    {
        if(Device.RuntimePlatform == Device.Android)
        {
            makeMargin = true;
            SetMargin();
            await Task.Delay(500);
            await JsRuntime.InvokeVoidAsync("scrollToInvisibleDiv", "focusBtn");
        }
    }
  3. Add JS function :

    window.scrollToInvisibleDiv = (div) => {
    document.getElementById(div).scrollIntoView();
    }
arivera12 commented 3 years ago

This looks like more like a dirty workaround rather than a solution. I did something like this before but was dirty workaround IMO. It's not a good workaround unless we don't need to listen to all inputs focus and blur events over blazor side. This needs to be worked on the android side inside the blazorwebview. For a decent workaround I think this should manage over pure JavaScript rather than over blazor side.

arivera12 commented 3 years ago

@Eilon I found a good and simple working solution doing 2 things!

@Slevya can you try and test my work around?

I moved the BlazorWebView out from it's main container:

Changed this:

<ContentView>
    <StackLayout>
        <BlazorWebView VerticalOptions="LayoutOptions.FillAndExpand">
            <HybridSolutionTemplate.WebUI.App />
        </BlazorWebView>
    </StackLayout>
</ContentView>

To this:

<BlazorWebView VerticalOptions="LayoutOptions.FillAndExpand">
    <HybridSolutionTemplate.WebUI.App />
</BlazorWebView>

And added this line of code in the App.cs inside the xamarin project after var host = hostBuilder.Build();

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

After that keyboard works perfectly I did few test on pages with pages with large forms and works just perfectly!

Source Modifications Screenshots

Main.razor image

App.cs image

It's seem the issue it's what I expected at the beginning the containers are not resizing well for some reason but at least this makes BlazorWebView work properly over android without any issues.

I still think this should be considered a bug for all reasons mentioned above.

idylmz commented 3 years ago

@arivera12 This definetely works for Android, thanks!

Haven't tried with iPhone though. But I didn't have any issues with iPhones.

arivera12 commented 3 years ago

@arivera12 This definetely works for Android, thanks!

Haven't tried with iPhone though. But I didn't have any issues with iPhones.

Thanks for the feedback!

Slevya commented 3 years ago

@Eilon I found a good and simple working solution doing 2 things!

@Slevya can you try and test my work around?

I moved the BlazorWebView out from it's main container:

Changed this:

<ContentView>
    <StackLayout>
        <BlazorWebView VerticalOptions="LayoutOptions.FillAndExpand">
            <HybridSolutionTemplate.WebUI.App />
        </BlazorWebView>
    </StackLayout>
</ContentView>

To this:

<BlazorWebView VerticalOptions="LayoutOptions.FillAndExpand">
    <HybridSolutionTemplate.WebUI.App />
</BlazorWebView>

And added this line of code in the App.cs inside the xamarin project after var host = hostBuilder.Build();

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

After that keyboard works perfectly I did few test on pages with pages with large forms and works just perfectly!

Source Modifications Screenshots

Main.razor image

App.cs image

It's seem the issue it's what I expected at the beginning the containers are not resizing well for some reason but at least this makes BlazorWebView work properly over android without any issues.

I still think this should be considered a bug for all reasons mentioned above.

Tested on Anrdoid 8.0 (Samsung Galaxy A3 - real device), Nexus 5x Api 28 (android 9.0), Pixel 2 Q 10.0 (Api 29 Anrdoid 10.0). Works perfectly

Eilon commented 3 years ago

Wow, great result!