xamarin / Xamarin.Forms

Xamarin.Forms is no longer supported. Migrate your apps to .NET MAUI.
https://aka.ms/xamarin-upgrade
Other
5.63k stars 1.88k forks source link

[Bug] Label with IsVisible = false takes up space #10325

Open oskarskog opened 4 years ago

oskarskog commented 4 years ago

Description

I have a basic list view page with some items and a header template containing a Label. The header label's visibility is toggled (data binding) every time I tap any of the items. Even if the label's IsVisible is false it still takes up space.

According to the docs this shouldn't happen: Setting IsVisible to false will remove the element from the visual tree. The element will no longer take up space in layouts or be eligle to receive any kind of input event.

Steps to Reproduce

With the attached sample code:

  1. Tap any list item
  2. Repeat from 1

Expected Behavior

Tapping on the items toggles the visibility of the header label. When the label is not visible it does not take up any space.

Actual Behavior

The label is hidden and shown when the IsVisible property is toggled but it still takes up space when IsVisible is false.

Basic Information

Screenshots

Screenshot_1586863547 Screenshot_1586863543

Reproduction Link

sample.zip

Workaround

Haven't been able to find something that works for me yet.

Some suggest wrapping the label in a StackLayout or a Grid with a row with Height="auto" but that has its own problems. E.g. the label doesn't become visible directly on the first time it's IsVisible is set to true, only after flipping the screen back and forth it shows up. Seems related to #4424

oskarskog commented 4 years ago

As a workaround I added the whole list, not just the label in the header, in a stacklayout, then the label disappears/appears as it should when IsVisible is toggled.

samhouts commented 4 years ago

I'm pretty sure this is the same as #10060. The problem isn't that the element continues to take up space; the problem is that the ListView isn't triggering a relayout when the contents change.

ianthetechie commented 4 years ago

Bump 2 months later? I'm not sure I agree that it's an issue with triggering a layout. The same behavior occurs even when IsVisible is set explicitly to False in the xaml and never toggled. So it could still be a layout issue, but it's not specific to re-triggering; it just never laid it out properly in the first place. I'm using X.F 4.7.0.968.

Here's a workaround for anyone coming across this in the meantime. This workaround feels hackish but does the job. In my case, this is a StackLayout on iOS, so both the problem and fix seem to be cross-platform and across the whole widget library.

<StackLayout Orientation="Vertical"
             Spacing="8"
             IsVisible="{Binding ShowFilterHeader}">
    <StackLayout.Triggers>
        <DataTrigger TargetType="StackLayout"
                     Binding="{Binding ShowFilterHeader}"
                     Value="false">
            <Setter Property="HeightRequest" Value="0" />
        </DataTrigger>
    </StackLayout.Triggers>
    ...
</StackLayout>
kasimier-vireq commented 1 year ago

Another issue with Labels not being removed from the visual tree is: Xamarin.UITest will return those Labels when using the All() query operatory. E.g. if we test the UI inside a ScrollView we need to use the All() operator in order to get all views inside the ScrollView - otherwise only the currently rendered views are returned.

Example: The following WaitForNoElement will produce an assertion error, because the label still exists in the visual tree although its IsVisible is false:

app.WaitForNoElement(q => q 
    .All()
    .Marked("MyScrollView")
    .Descendant()
    .Marked("SomeEntryInTheScrollView")
    .Index(0)
    .Descendant()
    .Marked("SomeLabelWithIsVisibleEqualsFalse"))

The only workaround I know of is to abandon WaitForNoElement and manually check whether Width and Height of that AppResult is zero.