I have a VerticalStackLayout inside a ScrollView. Some items inside the VerticalStackLayout are shown/hidden dynamically at runtime. I noticed that, on iOS, the VerticalStackLayout is shifted down (it’s Y position changes) inside the ScrollView when it has been scrolled and the visibility status of one of it’s children changes after that. I think this should not happen at all. On Android it behaves as expected (the VerticalStackLayout keeps at top).
Steps to reproduce:
- Create a new .NET MAUI App and change the XAML markup and code behind to the following:
XAML:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ScrollViewBug.MainPage">
<ScrollView x:Name="MyScroll">
<VerticalStackLayout
x:Name="MyStack"
Spacing="25"
Padding="30,0"
VerticalOptions="Start"
BackgroundColor="AliceBlue">
<Image
Source="dotnet_bot.png"
SemanticProperties.Description="Cute dot net bot waving hi to you!"
HeightRequest="200"
HorizontalOptions="Center" />
<Label
Text="Hello, World!"
SemanticProperties.HeadingLevel="Level1"
FontSize="32"
HorizontalOptions="Center" />
<Label
Text="Welcome to .NET Multi-platform App UI"
SemanticProperties.HeadingLevel="Level2"
SemanticProperties.Description="Welcome to dot net Multi platform App U I"
FontSize="18"
HorizontalOptions="Center" />
<Button
x:Name="CounterBtn"
Text="Click me"
SemanticProperties.Hint="Counts the number of times you click"
Clicked="OnCounterClicked"
HorizontalOptions="Center" />
<Grid x:Name="MyGrid" HeightRequest="600" BackgroundColor="Yellow" IsVisible="False"/>
</VerticalStackLayout>
</ScrollView>
</ContentPage>
Code behind:
using System.ComponentModel;
namespace ScrollViewBug;
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage()
{
InitializeComponent();
MyStack.PropertyChanged += StackPropertyChanged;
}
private void StackPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Y")
{
System.Diagnostics.Debug.WriteLine($"This Stack Y: {Math.Floor(MyStack.Y)}");
}
}
private void OnCounterClicked(object sender, EventArgs e)
{
count++;
if (count == 1)
CounterBtn.Text = $"Clicked {count} time";
else
CounterBtn.Text = $"Clicked {count} times";
MyGrid.IsVisible = !MyGrid.IsVisible;
SemanticScreenReader.Announce(CounterBtn.Text);
}
}
Is there a way to make a custom handler that keeps the ScrollView sub-views at place (Y=0) when the sub-view ContentSize changes?
I’ve tried to intercept changes on the ScrollView ContentSize using a custom handler, and replace the subview frame (changing it’s Y position to zero), but it had no effect.
I’m using Visual Studio for Mac 17.6.6 (build 408) + .NET 8 RC2.
2
Answers
I can reproduce your problem now. And the cause is the ScrollView doesn’t recalculate new size on iOS when the child’s visibility is changed to false.
You can use the following code to resolve it:
In the MauiProgram.cs:
I had the same issue and this didn’t fix it for me. I did a simple solution which is add TranslationY to the first child of the scrollview which is bound to the Y value of that same first child so that when Y changes (we don’t know why) the same value is added in negative to TranslationY. This in turn makes Y zero again fixing the issue.
The code used for this is the follows:
Here is the sample code for this:
I hope that helps someone out there. 😃