dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.06k stars 1.73k forks source link

[iOS] ScrollView not updating size when content size changes #15374

Open hartez opened 1 year ago

hartez commented 1 year ago

A vertically-oriented ScrollView should change the size of the viewport to match the size of the content if it's in a vertically unconstrained layout (like a VerticalStackLayout or a Grid's Auto row). This works as expected on Android and Windows, but on iOS the ScrollView isn't updating the viewport size when the content size changes.

jadenrogers commented 1 year ago

Example

XAML

<Grid RowDefinitions="Auto,*,Auto">

        <StackLayout Grid.Row="0" Padding="30" BackgroundColor="Aqua">
            <Label Text="Header" VerticalOptions="Center" HorizontalOptions="Center" />
        </StackLayout>

        <ScrollView Grid.Row="1" x:Name="Scroll">
            <VerticalStackLayout VerticalOptions="Start">
                <Border HeightRequest="800" x:Name="B1" BackgroundColor="Blue" IsVisible="False" />
                <Border x:Name="B2" HeightRequest="800" BackgroundColor="Red"  IsVisible="False" />
                <Border x:Name="B3" HeightRequest="800" BackgroundColor="Yellow"  IsVisible="False" />

                <Button 
                        Margin="20"
                        HeightRequest="50"
                        VerticalOptions="End"
                        Text="Hide/Show Blue button" 
                        Clicked="Button_Clicked_1" />

                <Button 
                        Margin="20"
                        HeightRequest="50"
                        VerticalOptions="End"
                        Text="Hide/Show Red button" 
                        Clicked="Button_Clicked_2" />

                <Button 
                        Margin="20"
                        HeightRequest="50"
                        VerticalOptions="End"
                        Text="Hide/Show Yellow button" 
                        Clicked="Button_Clicked_3" />
            </VerticalStackLayout>
        </ScrollView>

        <Button Grid.Row="2"
                Margin="20"
                Clicked="Button_Clicked"
                Text="Some button" />

    </Grid>

Code Behind

using Microsoft.Maui.Controls;
using Microsoft.Maui.Handlers;

namespace Maui.Controls.Sample;

public partial class Fails : ContentPage
{
    public Fails()
    {
        InitializeComponent();
    }

    private void Button_Clicked(object sender, System.EventArgs e)
    {
        DisplayAlert("Alert", "You clicked me!", "OK");
    }

    private void Button_Clicked_1(object sender, System.EventArgs e)
    {
        B1.IsVisible = !B1.IsVisible;       
    }

    private void Button_Clicked_2(object sender, System.EventArgs e)
    {
        B2.IsVisible = !B2.IsVisible;
    }

    private void Button_Clicked_3(object sender, System.EventArgs e)
    {
        B3.IsVisible = !B3.IsVisible;
    }
}
ghost commented 1 year ago

We've added this issue to our backlog, and we will work to address it as time and resources allow. If you have any additional information or questions about this issue, please leave a comment. For additional info about issue management, please read our Triage Process.

xtuzy commented 1 year ago

Hello, I don't know if my bug is related.

I copy @jadenrogers 's code from https://github.com/dotnet/maui/issues/14257#issuecomment-1646408225 can solve some bugs of ScrollView.

But 2 weeks ago, I have a issue https://github.com/dotnet/maui/issues/16711 about RefreshView+ScrollView+Border don't have SizeChanged event

Today, find RefreshView+ScrollView+Border also let Content's Size only increase, not decrease. use @jadenrogers 's code don't solve it , code see https://github.com/xtuzy/net8preview7_refeshviewborderbug/blob/master/MauiApp1/ScrollViewSizeBug.xaml.cs

jadenrogers commented 1 year ago

Hello, I don't know if my bug is related.

I copy @jadenrogers 's code from #14257 (comment) can solve some bugs of ScrollView.

But 2 weeks ago, I have a issue #16711 about RefreshView+ScrollView+Border don't have SizeChanged event

Today, find RefreshView+ScrollView+Border also let Content's Size only increase, not decrease. use @jadenrogers 's code don't solve it , code see https://github.com/xtuzy/net8preview7_refeshviewborderbug/blob/master/MauiApp1/ScrollViewSizeBug.xaml.cs

Yes your example doesn't work. But tweaking your cs file like below it does. It's still a Border in a Scroll in a Refresh view. Grows and shrinks fine with handler fix in place.


public partial class ScrollViewSizeBug : ContentPage
{
    private readonly Border _border;

    public ScrollViewSizeBug()
    {
        _border = new Border()
        {
            VerticalOptions = LayoutOptions.Start,
            BackgroundColor = Colors.Red,
            Content = new Button() { Margin = 10, HeightRequest = 50, Text = "Testing" }
        };
        InitializeComponent();

        var refreshView = new RefreshView();
        var scrollView = new ScrollView();

        refreshView.Content = scrollView;
        grid.Add(refreshView);
        Grid.SetRow(refreshView, 1);
        scrollView.Content = _border;
    }

    private void Button_Clicked(object sender, EventArgs e)
    {
        _border.HeightRequest += 100;
    }

    private void Button_Clicked_1(object sender, EventArgs e)
    {
        _border.HeightRequest -= 100;
    }
}
xtuzy commented 1 year ago

Hello, I don't know if my bug is related. I copy @jadenrogers 's code from #14257 (comment) can solve some bugs of ScrollView. But 2 weeks ago, I have a issue #16711 about RefreshView+ScrollView+Border don't have SizeChanged event Today, find RefreshView+ScrollView+Border also let Content's Size only increase, not decrease. use @jadenrogers 's code don't solve it , code see https://github.com/xtuzy/net8preview7_refeshviewborderbug/blob/master/MauiApp1/ScrollViewSizeBug.xaml.cs

Yes your example doesn't work. But tweaking your cs file like below it does. It's still a Border in a Scroll in a Refresh view. Grows and shrinks fine with handler fix in place.

public partial class ScrollViewSizeBug : ContentPage
{
    private readonly Border _border;

    public ScrollViewSizeBug()
    {
        _border = new Border()
        {
            VerticalOptions = LayoutOptions.Start,
            BackgroundColor = Colors.Red,
            Content = new Button() { Margin = 10, HeightRequest = 50, Text = "Testing" }
        };
        InitializeComponent();

        var refreshView = new RefreshView();
        var scrollView = new ScrollView();

        refreshView.Content = scrollView;
        grid.Add(refreshView);
        Grid.SetRow(refreshView, 1);
        scrollView.Content = _border;
    }

    private void Button_Clicked(object sender, EventArgs e)
    {
        _border.HeightRequest += 100;
    }

    private void Button_Clicked_1(object sender, EventArgs e)
    {
        _border.HeightRequest -= 100;
    }
}

Sorry, i made a mistake, my example is refreshview+scrollview+layout+border = not work, your example is refreshview+scrollview+border = work. I'm building a collectionview use scrollview+layout, so i need layout.

mstefarov commented 1 year ago

I think I am running into this issue as well. Here is a simplified repro:

<ContentPage xmlns="...">
    <Border HorizontalOptions="Center" VerticalOptions="Center" Background="Red" Padding="20">
        <ScrollView Background="Orange" MaximumWidthRequest="400">
            <StackLayout x:Name="TheContentStack" />
        </ScrollView>
    </Border>
</ContentPage>
public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
        this.Loaded += MainPage_Loaded;
    }

    private async void MainPage_Loaded(object sender, EventArgs e)
    {
        await Task.Delay(1000);
        for (int i = 0; i < 10; i++)
        {
            TheContentStack.Children.Add(new Label
            {
                Text = "This is a fairly long text inside a label number " + i,
                LineBreakMode = LineBreakMode.WordWrap,
                TextColor = Colors.Black,
            });
        }
    }
}

20230914_170201

So I've got a centered Border with a ScrollView, whose contents are dynamically populated. All platforms behave a bit differently here. WinUI's ScrollView fits to content, Android ScrollView always just fills the page, but iOS ScrollView starts and stays collapsed even after I add content -- and even after calling ForceLayout. The only way I get those ScrollView contents to show up is to rotate the phone a couple times.

xtuzy commented 1 year ago

add HorizontalOptions="Center" VerticalOptions="Center" to ScrollView , Android same with Windows

image

jadenrogers commented 1 year ago

Hi @mstefarov Are you using the Handler fix from here https://github.com/dotnet/maui/issues/14257#issuecomment-1646408225

This should address the ios issue of it not growing.

@xtuzy I still need to look more into that, not up to the play with the LayoutManagers

mstefarov commented 1 year ago

@jadenrogers The workaround helps a lot. The ScrollView no longer stays collapsed!

Though, layout on iOS still ends up a little different from Windows/Android. On iOS the width of ScrollView/StackLayout now gets tightly fitted to its content, but on other platforms they end up matching MaximumWidthRequest. To be honest, I'm not even sure which is correct, but either behavior works for me.

20230915_103433

jadenrogers commented 1 year ago

@mstefarov I think if you remove the HorizontialOptions or set it to fill it should look the same?

ewerspej commented 11 months ago

Hi @mstefarov Are you using the Handler fix from here #14257 (comment)

This should address the ios issue of it not growing.

@jadenrogers This workaround only works in simple scenarios, e.g.:

<ScrollView>
    <VerticalStackLayout>
        <!-- expandable content goes here -->
    </VerticalStackLayout>
</ScrollView>

but it fails as soon as there are more nesting levels, even wrapping the VerticalStackLayout with a Grid fails already, e.g.:

<ScrollView>
    <Grid>
        <VerticalStackLayout>
            <!-- expandable content goes here -->
        </VerticalStackLayout>
    </Grid>
</ScrollView>

Repro: https://github.com/ewerspej/MauiBugScrollViewSizingiOS

ahmedHashwa commented 11 months ago

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:

  1. First add static resource for MathsExpressionConverter
  2. Then add binding for TranslationY so that it references Y property of the same view under ScrollView

Here is the sample code for this:

<?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"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             x:Class="TestMaui.MainPage">
    <ContentPage.Resources>
        <ResourceDictionary>
            <toolkit:MathExpressionConverter x:Key="MathExpressionConverter" />
        </ResourceDictionary>
    </ContentPage.Resources>
    <ScrollView>
        <!--Any child like VerticalStackLayout-->
        <VerticalStackLayout TranslationY="{Binding Source={RelativeSource Self}, Path=Y, Converter={StaticResource MathExpressionConverter}, ConverterParameter='-1*x' }" >
           <!--Any content-->
        </VerticalStackLayout>
    </ScrollView>
</ContentPage>

I hope that helps someone out there. 😃

ewerspej commented 11 months ago
  1. First add static resource for MathsExpressionConverter
  2. Then add binding for TranslationY so that it references Y property of the same view under ScrollView

@ahmedHashwa That's an interesting workaround. Does this work with nested layouts where the content is subject to changes in height?

Brosten commented 6 months ago

I'm having multiple issues related to this bug. Any progress around fixing it?

Divyesh-Bhatt commented 3 months ago

This issue still exists.

SchittkowskiMS commented 1 month ago

This issue is still happening