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.24k stars 1.76k forks source link

Buttons offscreen inside ScrollView do not work on iOS #15283

Open LukeFranky opened 1 year ago

LukeFranky commented 1 year ago

Description

I am running into bug after bug with MAUI. The latest one is a showstopper.

As soon as a button is pushed offscreen by content inside a ScrollView, the button clicked event will never fire. This is very simple to reproduce on the standard MAUI project template by extending the last label to push the button off screen.

2023-05-26 08_23_39-Scrolling Button MAUI Bug (Running) - Microsoft Visual Studio (Administrator)

I cannot believe Microsoft considered MAUI ready. It is too buggy for even a beta release let alone a general release. I appreciate the developers are doing their best, and I do not blame them, but Microsoft need to hear some honest feedback. They're burning through a lot of goodwill.

Maybe this isn't the right forum for the feedback, but my frustration is boiling over. How can something a simple as having a button pushed off screen in a ScrollView not work? Makes me worried if we ever get to the point of releasing an app built MAUI, will it function consistently for end users? That will reflect on our work quality too.

Steps to Reproduce

  1. Create a new MAUI project.
  2. Run the app on iOS.
  3. Add HeightRequest="500" to the last Label via Hot Reload (or via code).
  4. Try tapping the button.

Link to public reproduction project repository

https://github.com/LukeFranky/Scrolling-Button-MAUI-Bug

Version with bug

7.0.86

Last version that worked well

Unknown/Other

Affected platforms

iOS

Affected platform versions

16.4, 16.1.1

Did you find any workaround?

Edit: Yes. Toggle ScrollView.IsVisible to false and back to true after the scroll content has changed size. Scroll.IsVisible = false; Scroll.IsVisible = true;

Relevant log output

No response

LukeFranky commented 1 year ago

I have discovered some further detail: The button works when the content stays a set size, but the moment anything is dynamically resized, either through XAML hot reload or by altering the content with code, the button stops functioning.

LukeFranky commented 1 year ago

Hiding and reshowing the ScrollView is a workaround:

    private void OnCounterClicked(object sender, EventArgs e)
    {
        count++;

        if (count == 1)
            CounterBtn.Text = $"Clicked {count} time";
        else
            CounterBtn.Text = $"Clicked {count} times";

        Label1.HeightRequest = 500;

        Scroll.IsVisible = false;
                Scroll.IsVisible = true;

                SemanticScreenReader.Announce(CounterBtn.Text);
    }
xufeitt commented 1 year ago

add Scroll.IsVisible = false; Scroll.IsVisible = true;

android will not display the scroll

Did you find that?

jadenrogers commented 1 year ago

@LukeFranky I know this all to well. Broke my whole app. Anything involving a scroll where content grows is problematic. The child container doesn't grow and what you see is technically overflowed its container uncropped causing this "I can see it but can't click it problem".

I tested your code and its fixed by https://github.com/dotnet/maui/pull/15460 if it gets approved.

While we wait another fix someone else suggested is add SizeChanged="OnSizeChanged" to your VerticalStackLayout, add a name to your scroll and add (NameOfYourScroll as IView).InvalidateMeasure(); in your size changed event which does solve it for the moment.

Understanding the problem a bit more you can use this 'FixedScrollView' class in place of your ScrollView.

    public class FixedScrollView : ScrollView
    {
        public new View Content
        {
            get
            {
                return base.Content;
            }
            set
            {
                if (value == null && base.Content != null)
                    base.Content.SizeChanged -= Content_SizeChanged;
                else if (value != null)
                    value.SizeChanged += Content_SizeChanged;

                base.Content = value;
            }
        }

        void Content_SizeChanged(object sender, EventArgs e)
        {
            #if IOS
            InvalidateMeasure();
            #endif
        }
    }
XamlTest commented 1 year ago

Verified this on Visual Studio Enterprise 17.7.0 Preview 3.0. Repro on iOS 16.4 .NET 8, not repro on Windows 11 and Android 13.0-API33 with below Project: Scrolling Button MAUI Bug.zip

denhaandrei commented 1 year ago

Hi @jadenrogers , @LukeFranky

@LukeFranky I know this all to well. Broke my whole app. Anything involving a scroll where content grows is problematic. The child container doesn't grow and what you see is technically overflowed its container uncropped causing this "I can see it but can't click it problem".

I tested your code and its fixed by #15460 if it gets approved.

While we wait another fix someone else suggested is add SizeChanged="OnSizeChanged" to your VerticalStackLayout, add a name to your scroll and add (NameOfYourScroll as IView).InvalidateMeasure(); in your size changed event which does solve it for the moment.

Understanding the problem a bit more you can use this 'FixedScrollView' class in place of your ScrollView.

For me it does not work when ScrollView positioned into RefreshView=(

jadenrogers commented 1 year ago

Hi @denhaandrei

Ah yes I came up with a new and improved fix here https://github.com/dotnet/maui/issues/14257#issuecomment-1646408225

That works when inside a RefreshView, just use the regular ScrollView control and add the new code in your MauiProgram somewhere

denhaandrei commented 1 year ago

Hi @denhaandrei

Ah yes I came up with a new and improved fix here #14257 (comment)

That works when inside a RefreshView, just use the regular ScrollView control and add the new code in your MauiProgram somewhere

It's worked fine for me

Thanks for your help!

MsVibe commented 1 year ago

Bug is also present in MacCatalyst