2

I have a login page with 3 Entry controls under a large image logo and a Button control at the bottom of the page, when I click on the top Entry control to bring the Entry into focus to start typing, the keyboard appears and covers up the Entry controls below and the Login button which is not the best user experience.

The user can only scroll up manually on Xamarin.Forms.iOS but using the same code, ScrollToAsync, on Android I have been able to make the Entry on focus scroll to the top of page by grabbing the parent ScrollView and doing "ScrollView.ScrollToAsync(EntryControl, ScrollToPosition.Start, true);"

On Android, the button at the bottom of the page also moves up by using a * in the Grid Row definition of the empty space in the middle.

It seems like Xamarin.Forms.iOS behaves completely different to Xamarin.Forms.Android when rendering. I have seen the ScrollToAsync has some issues on iOS on page load due to the ScrollView not existing until the page has fully loaded. But this action is on a page that has already fully rendered. What am I doing wrong?

I have tried a Delay as mentioned in this SO, but it doesn't help. ScrollToAsync is not working in Xamarin.Forms

XAML

<Grid>
    <ScrollView VerticalOptions="FillAndExpand"
                BackgroundColor="White"
                x:Name="ScrollViewContainer"
                >
        <Grid Margin="15, 0, 15, 10">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" /><!--Logo-->
                <RowDefinition Height="Auto" /><!--Entry1-->
                <RowDefinition Height="Auto" /><!--Entry2-->
                <RowDefinition Height="Auto" /><!--Entry3-->                    
                <RowDefinition Height="*" />
                <RowDefinition Height="Auto" /><!--Button-->
                <RowDefinition Height="20" /><!--Empty padding-->
            </Grid.RowDefinitions>
            <Image Grid.Row="0"                
                   Aspect="AspectFit"
                   Source="CompanyLogo"
                   HorizontalOptions="Start"
                   HeightRequest="300"
                   VerticalOptions="Start"
                   Margin="10, 20, 20, 0"
                   />
             <Entry Grid.Row="1"
                    x:Name="BranchName"
                    Placeholder="BranchName" 
                    Focused="BranchName_Focused"
                    />   
             <Entry Grid.Row="2"
                    x:Name="Username"
                    Placeholder="e.g. Batman "
                    Focused="Username_Focused"
                    />  
             <Entry Grid.Row="3"
                    x:Name="Password"
                    Placeholder="Enter your password"
                    Focused="Password_Focused"
                    IsPassword="True"
                    />              
             <Button Grid.Row="5"
                     x:Name="LoginButton"
                     Text="Log in"
                     />
        </Grid>
    </ScrollView>
</Grid>

Code Behind

    private async void BranchName_Focused(object sender, FocusEventArgs e)
    {
        await ScrollViewContainer.ScrollToAsync(BranchName, ScrollToPosition.Start, true);
    }
xleon
  • 6,201
  • 3
  • 36
  • 52

3 Answers3

3

The solution was in part by @numan98 answer above which got me re-taking another look at the microsoft docs, https://learn.microsoft.com/en-us/dotnet/api/xamarin.forms.scrollview.scrolltoasync?view=xamarin-forms

It states that ScrollToAsync(double X, double Y, bool animate) will be the final double position values of where X and Y should be.

Thus, X doesn't move anywhere, so I believe it should be 0, and Y I just gave an arbitrary number, such as 250. Somewhere close to the top I believe.

After, we have that iOS bug again where you need to put in a delay.

The final code looks something like this.

private async void BranchName_Focused(object sender, FocusEventArgs e)
{
    Device.StartTimer(TimeSpan.FromSeconds(0.25), () =>
    {
        scroll.ScrollToAsync(0, 250, true);
        return false;
    );
}

I hope this helps someone. The next thing now is to get the CTA button to move and always be in view.

0

Add this in your xaml.cs file

 protected override void OnAppearing()
    {
        base.OnAppearing();
        userName.Focused += InputFocused;
        password.Focused += InputFocused;
        userName.Unfocused += InputUnfocused;
        password.Unfocused += InputUnfocused;
    }

    protected override void OnDisappearing()
    {
        base.OnDisappearing();
        userName.Focused -= InputFocused;
        password.Focused -= InputFocused;
        userName.Unfocused -= InputUnfocused;
        password.Unfocused -= InputUnfocused;
    }
    void InputFocused(object sender, EventArgs args)
    {
        Content.LayoutTo(new Rectangle(0, -270, Content.Bounds.Width, Content.Bounds.Height));
    }

    void InputUnfocused(object sender, EventArgs args)
    {
        Content.LayoutTo(new Rectangle(0, 0, Content.Bounds.Width, Content.Bounds.Height));
    }
Anand
  • 1,866
  • 3
  • 26
  • 49
  • Hi, thank you for your answer, I had just tried this and it did not work. Maybe I am missing something. From the Microsoft docs https://learn.microsoft.com/en-us/dotnet/api/xamarin.forms.viewextensions.layoutto?view=xamarin-forms and this http://xfcomplete.net/xamarin.forms/2016/01/14/layoutto-doesnt-do-what-you-think-it-does/ can you explain how LayoutTo can help with the solution to the problem? Thanks – CookieMonster Oct 10 '19 at 14:09
  • Hi, You can refer this link https://stackoverflow.com/questions/39641429/xamarin-forms-move-the-view-upward-according-to-keyboard-height/39641733#39641733 – Anand Oct 10 '19 at 14:14
  • Didn't help but thank you. I actually require the exact same effect and the plugin in your SO link didn't work for me neither. I found another solution – CookieMonster Oct 11 '19 at 08:37
  • @CookieMonster Okey Happy coding bro. +1 from me – Anand Oct 11 '19 at 08:55
-1

I think you should try this...

private async void BranchName_Focused(object sender, FocusEventArgs e)
{
   await ScrollViewContainer.ScrollToAsync(BranchName.Bounds.X, BranchName.Bounds.Y, true);
}
Eray Balkanli
  • 7,752
  • 11
  • 48
  • 82
  • Yes, reading MS docs I realize that there are 2x ways to overload this method. https://learn.microsoft.com/en-us/dotnet/api/xamarin.forms.scrollview.scrolltoasync?view=xamarin-forms – CookieMonster Oct 11 '19 at 08:38