简体   繁体   中英

Xamarin Forms ScrollView is not scrolling correctly

We have an instant message app. We want to scroll automatically when a message is received so the new message is visible. Currently, when the first message that requires scrolling is received, the page does not scroll. That is, the new message is hidden behind our input controls. It requires another message or the user to adjust the scrollview and then it works properly.

Our xaml is something like this:

<ContentPage>
  <StackLayout x:Name="mainStackLayout">
    <customControls:NavBar />
    <ScrollView x:Name="mainScrollView">
      <StackLayout x:Name="mainScrollViewStackLayout">
        <ScrollView x:Name="messagesScrollView">
          <StackLayout x:Name="messagesScrollViewContentStackLayout">
            <!-- Messages are programmatically inserted here -->
          </StackLayout>
        </ScrollView>
      </StackLayout>
    </ScrollView>
    <StackLayout>
      <!-- a couple buttons/inputs for sending messages -->
    </StackLayout>
  </StackLayout>
</ContentPage>

And the code we call to scroll looks like this:

public void ScrollMessagesToEnd()
{

    StackLayout messagesContent = (messagesScrollView.Content as StackLayout);
    var frame = messagesContent.Children.LastOrDefault();

    if (frame != null)
    {
            messagesScrollView.ScrollToAsync(frame, ScrollToPosition.MakeVisible, true);
    }
}

Regardless of the solution, ScrollMessagesToEnd should be made async and you need to await ScrollToAsync() . Since you are now awaiting ScrollToAsync() , I would suggest explicitly running it on the UI thread.

After that, is done, you might try adding await Task.Delay(300) to the top of your method, I have had to do that before.

You may also want to try enabling and disabling animation which I have found can effect scrolling but test it on each platform since the effect will probably be different on each.

public async Task ScrollMessagesToEndAsync() //Adding Async to method name, also try to return Task and await this method in the calling code as well
{
    await Task.Delay(300); //Sometimes code runs too fast and a delay is needed, you may test whether only a specific platform needs the delay

    StackLayout messagesContent = (messagesScrollView.Content as StackLayout);
    var frame = messagesContent.Children.LastOrDefault();

    if (frame != null)
    {
        Device.BeginInvokeOnMainThread(async () => await messagesScrollView.ScrollToAsync(frame, ScrollToPosition.MakeVisible, true)); //You could try passing in false to disable animation and see if that helps
    }
}

I would strongly recommend NOT use nested scroll views but if you keep them then here is the solution.

Instead

messagesScrollView.ScrollToAsync(frame, ScrollToPosition.MakeVisible, true);

Use

mainScrollView.ScrollToAsync(frame, ScrollToPosition.End, true);

or

mainScrollView.ScrollToAsync(frame, ScrollToPosition.MakeVisible, true);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM