Search code examples
c#iosmaui

.NET MAUI InvalidateMeasure on ScrollView won't reset height when within a RefreshView on iOS


When records are removed (via pull down refresh) the ScrollView doesn't resize (shrink in height) based on the new content length, which it should provided: (svMain as IView).InvalidateMeasure();

The following works on Android, but not on iOS.

To reproduce:

  1. 10 items are preloaded
  2. Click the "Add 10" button
  3. Pull-down from the top to refresh

ReportsPage.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="testrv.ReportsPage"
             Title="ReportsPage">
    <Grid x:Name="gridMain">

        <Grid.RowDefinitions>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>

        <RefreshView x:Name="rvMain" Grid.Row="0" IsRefreshing="{Binding IsRefreshing}" Command="{Binding RefreshCommand}" RefreshColor="{DynamicResource Primary}">
            <ScrollView x:Name="svMain">

                <Grid Margin="20">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="50" x:Name="gridMain_row_0"></RowDefinition>
                        <RowDefinition Height="*" x:Name="gridMain_row_1"></RowDefinition>
                        <RowDefinition Height="60" x:Name="gridMain_row_2"></RowDefinition>
                    </Grid.RowDefinitions>

                    <VerticalStackLayout Grid.Row="0" x:Name="vslHeader" Spacing="10"></VerticalStackLayout>

                    <VerticalStackLayout Grid.Row="1" x:Name="vslBody" Spacing="10" VerticalOptions="Start">

                        <Button Clicked="Button_Clicked" Text="Add 10"></Button>

                        <VerticalStackLayout x:Name="vslFeed" Spacing="10" BindableLayout.ItemsSource="{Binding Labels}">
                            <BindableLayout.ItemTemplate>
                                <DataTemplate>
                                    <Label Text="{Binding .}" BackgroundColor="Azure"></Label>
                                </DataTemplate>
                            </BindableLayout.ItemTemplate>
                        </VerticalStackLayout>
                    </VerticalStackLayout>

                    <VerticalStackLayout Grid.Row="2" x:Name="vslFooter" Spacing="10"></VerticalStackLayout>

                </Grid>

            </ScrollView>
        </RefreshView>

    </Grid>
</ContentPage>

ReportsPage.xaml.cs

using System.Collections.ObjectModel;
using System.Windows.Input;

namespace testrv;

public partial class ReportsPage : ContentPage
{

    ObservableCollection<string> Labels = new ObservableCollection<string>();

    public ReportsPage()
    {
        InitializeComponent();

        BindableLayout.SetItemsSource(vslFeed, Labels);
    }

    protected async override void OnAppearing()
    {
        base.OnAppearing();

        await SetLabels();

        ICommand refreshCommand = new Command(async () =>
        {
            // IsRefreshing is true
            rvMain.IsRefreshing = true;
            await SetLabels();
            rvMain.IsRefreshing = false;

            (svMain as IView).InvalidateMeasure();
        });
        rvMain.Command = refreshCommand;
    }

    private async Task SetLabels()
    {
        Labels.Clear();

        for (int i = 0; i < 10; i++)
        {
            AddLabel();
        }
    }

    private void AddLabel()
    {
        Labels.Add("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam feugiat tincidunt lacinia. " +
            "Fusce at magna et odio finibus consectetur vel vel velit. Integer eu felis vel lorem efficitur semper sed sagittis justo. " +
            "Mauris hendrerit ex semper augue posuere ornare. Vestibulum rhoncus commodo risus, id interdum nibh dictum nec.");
    }

    private void Button_Clicked(object sender, EventArgs e)
    {
        for (int i = 0; i < 10; i++)
        {
            AddLabel();
        }
    }
}

Solution

  • I upgraded from .NET7 to .NET8 and it solved the issue.