ScrollView ScrollToAsync behaviour

edammeredammer GBMember ✭✭

Hi,

I have been having issues with using the ScrollToAsync function of a ScrollView when running on Android, not tested on iOS yet.
I'm using Xamarin.Forms version 2.5.1.444934 using .Net Standard
Testing on the Android Emulator (8.0, API26) and a Google Pixel (8.1 API27), both have the same issue.

I use NavigationPage and Navigation.PushAsync to move between pages (therefore have navigation bars on every page).

I want to create an auto populate field control, the user types in the first few letters and I look up the results in a database / static list of string and display the results below for the user to click/tap.
I have this working using a composite control (the contents of the frame marked interesting below).
The problem I have is scrolling the view to show the results.

My page has this layout hierarchy:-

ContentPage
    StackLayout
        ScrollView
            StackLayout
                Frame (some label and entry fields inside a stack layout)
                Frame (some label and entry fields inside a stack layout)
                Frame (some label and entry fields inside a stack layout)
                Frame (the interesting one that deals with scrolling)
                    StackLayout
                        Heading Label
                        StackLayout
                            Label x:Name="ScrollToLabel"
                            Entry x:Name="ScrollToEntry"
                            Grid x:Name="ScrollToGrid"
                            Entry x:Name="Hidden" Text="I should stay visible as you type"
                        /StackLayout
                    /StackLayout
                /Frame
                Frame (some label and entry fields inside a stack layout)
                Frame (some label and entry fields inside a stack layout)
            /StackLayout
        /ScrollView
        StackLayout
            Button Text = Done
        /StackLayout
    /StackLayout
/ContentPage

When the user clicks/taps in to ScrollToEntry, the keyboard opens and pans the control to above the keyboard (ok so far).
When the user starts typing in ScrollToEntry, the code populates ScrollToGrid with up to 5 results.
At this point I want to make sure that the grid results are visible for the user to tap on.
I have tried 2 different options, ScrollToAsync(ScrollToLabel, Start) and ScrollToAsync(Hidden, MakeVisible).

Neither work as I would like 100% of the time.

ScrollToAsync(ScrollToLabel, Start)

If the ScrollToEntry is at the bottom of the screen, the navigation bar is hidden and the view pans up too far.
The ScrollToLabel is now off the top of the screen.
When the second letter is clicked/tapped, the Navigation bar is restored and the scroll scrolls correctly, ScrollToLabel at the top of the screen.
If the ScrollToEntry is near the top of the screen, the navigation bar is not hidden and it scrolls correctly.

ScrollToAsync(Hidden, MakeVisible)
This is my preferred option because it would only scroll as far as needed to display all the results (not all the way to the top).
This works even worse than the first one.
In most cases, it does not scroll at all, I assume it thinks it already visible but is actually behind the keyboard?
If it does scroll, the label Hidden is still not displayed (I tested with both a HeightRequest="0" version and a visible version, both the same result).

I tried using the below code to change the adjust to resize.
Application.Current.On<Xamarin.Forms.PlatformConfiguration.Android>().UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize);

2 issues,
1. Because it resizes, the Done button now is above the keyboard, taking up space.
2. When clicking the hardware back button (not the done or navigation back button) the previous view now has a white space where the keyboard was.
If using the done or navigation back, the screen initially appears with the white space but then refreshes to full screen.

I have created a sample app that highlights the issues (by default using pan, not resize) attached.
Its the most simple version of the layout I'm using.

Am I doing something wrong or is this just how it works?
If its how it works, this must be a bug?
If I'm doing it wrong, can someone tell me what or suggest a different way of doing it?

Thanks

Answers

  • edammeredammer GBMember ✭✭

    Further update.
    Now that I can build for iOS as well (thanks appcenter), I have noticed that the scrollTo on iOS does not seem to work at all.

  • edammeredammer GBMember ✭✭

    Also, upgrading to xamarin.forms v3 did not fix the issue.

  • edammeredammer GBMember ✭✭

    Any one have any ideas about this?
    Is ScrollView.ScrollTo just broken or am I doing something wrong.

  • hatefkinmycodehatefkinmycode USMember ✭✭

    @edammer did you ever get an answer? I'm having similar issues on Xamarin Android for a ScrollView with a StackLayout inside. Everything works great in UWP.

  • edammeredammer GBMember ✭✭
    > @hatefkinmycode said:
    > @edammer did you ever get an answer? I'm having similar issues on Xamarin Android for a ScrollView with a StackLayout inside. Everything works great in UWP.

    Hi, not worked on this app for a while but when I last tried it the issue was still there.
    I was looking at other ways of doing it, like a modal view.
  • hatefkinmycodehatefkinmycode USMember ✭✭

    @edammer have you looked at an async method? I'm toying with this one after hitting my head against the wall. I want to do some more research on the Task.Run and Task.StartRun calls before I settle on this method, but here's what I have and it works on Android and UWP.

    in your view's OnSizeAllocated, toss in some code to scroll. You could probably do this in a Page's OnAppearing but I'm working within a Custom View inside a Page, so hence my OnSizeAllocated usage...

            protected override async void OnSizeAllocated(double width, double height)
            {
                base.OnSizeAllocated(width, height);
    
                //scroll the menu to the far right.  
                Task scrollTask = Task.Factory.StartNew(async () => {
                    await ScrollToEndAsync();
                }, CancellationToken.None, TaskCreationOptions.AttachedToParent, TaskScheduler.FromCurrentSynchronizationContext());
    
            }
    

    where ScrollToEndAsync() is just a helper to talk to "barScroll" which is my ScrollView wrapped over a StackLayout...

    private async Task ScrollToEndAsync()
            {
                await Task.Delay(250);
                //paranoid async check
                if (barScroll == null)
                {
                    Debug.WriteLine("BreadcrumbBar tried to scroll on a null barscroll");
                    return;
                }
    
                double scrollTarget = barScroll.ContentSize.Width - barScroll.Width;
                await barScroll.ScrollToAsync(scrollTarget, barScroll.ScrollY, true);
            }
    

    If anyone can speak to the thread safety of doing this or other issues, I'm all ears.

  • hatefkinmycodehatefkinmycode USMember ✭✭

    Don't use that code. It's not thread-safe, like I suspected. That ScrollView gets disposed and then will throw exceptions later. I'll keep messing with it and post an answer if I find one.

  • edammeredammer GBMember ✭✭

    @hatefkinmycode said:
    Don't use that code. It's not thread-safe, like I suspected. That ScrollView gets disposed and then will throw exceptions later. I'll keep messing with it and post an answer if I find one.

    Are you using the latest Xamarin.Forms version?
    I was "fingers crossed" that this was going to be fixed by the time I worked on it again.

    I don't think I'm going anything crazy in my code/layout so assumed that loads of others would be having the same issue as me.

    I was hoping someone from the Xamarin Dev team would have had a look at this by now.
    I posted the code to reproduce the issue.

  • hatefkinmycodehatefkinmycode USMember ✭✭

    hey @edammer I'm on Forms 3.4.0.1009999 I am just ditching my need for the ScrollView and will code around the problem. It's kinda lame, but waiting for a fix is not an option for me atm.

Sign In or Register to comment.