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);
}
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.