xamarin / Xamarin.Forms

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

FlexLayout height not rendered correctly when placed inside Grid #5265

Open xyfoo opened 5 years ago

xyfoo commented 5 years ago

Description

FlexLayout (without explicit HeightRequest) placed inside a Grid's Row (Height="Auto"), the FlexLayout will be rendered as the same height as the Grid.

Observation

Steps to Reproduce

  1. Create a new Forms project and update to v 3.5.0.129452
  2. Add the following
    <Grid x:Name="grid" RowSpacing="0">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <BoxView Grid.Row="0" BackgroundColor="Red" VerticalOptions="FillAndExpand"/>
        <FlexLayout x:Name="flex" Grid.Row="1" BackgroundColor="Yellow">
            <Button Text="Check Height" Clicked="CheckHeight_Clicked" HeightRequest="40" />
        </FlexLayout>
        <BoxView Grid.Row="2" BackgroundColor="Green" VerticalOptions="FillAndExpand"/>
    </Grid>
  3. Run the app

Expected Behavior

Actual Behavior

Basic Information

Screenshots

bug

Actual behavior vs Expected behavior

Reproduction Link

xfbug.zip

pauldipietro commented 5 years ago

Also tested against the latest 4.0-pre

nbevans commented 5 years ago

I believe I'm seeing the same issue on UWP.

nbevans commented 5 years ago

https://github.com/xamarin/Xamarin.Forms/blob/50dbbcf55d71f75fa79aa87e8514799b322f3bda/Xamarin.Forms.Core/FlexLayout.cs#L401

Likely caused by this.

nbevans commented 5 years ago

I created this (F#) workaround which sort of fixes the issue for me - though it's not perfect, it is bit glitchy when resizing the UWP window.

Something is really wrong with that OnMeasure method in the core implementation of XF.

type FlexLayout_HackFix20190326() =
    inherit FlexLayout()

    override self.OnMeasure(widthConstraint, heightConstraint) =
        let height = self.Children |> Seq.map (fun c -> c.Measure(Double.PositiveInfinity, Double.PositiveInfinity).Request.Height + c.Bounds.Top) |> Seq.maxBy id
        base.OnMeasure(widthConstraint, height)
nbevans commented 5 years ago

Will this ever be fixed? It basically makes FlexLayout unusable. My "fix" above isn't really good enough - it's too glitchy for production use.

rotorgames commented 5 years ago

The same for me

DoubleDBE commented 5 years ago

Same here. I'm temporary wrapping the FlexLayout inside a StackLayout until this issue is solved.

rotorgames commented 5 years ago

@DoubleDBE Wrapping StackLayout can help. Also, we can get the same behavior as StackLayout if we override OnMeasure in FlexLayout and change widthConstrain or heigthContrain to double.PositinInfinity. But FlexLayout calculates the size of elements inside incorrectly. For example, when I put Label with long text, Grow = 0.5 and WordWrap inside FlexLayout I got incorrect label height and the text was cut.

acastr7 commented 5 years ago

Just ran into this issue with a FlexLayout out inside my ViewCell. Wrapping in StackLayout as a work around helped.

YZahringer commented 5 years ago

Same problem, here is an example where the FlexLayout should be aligned at the beginning at the top but it takes all the space horizontally and vertically.

    <Grid
        BackgroundColor="Yellow"
        HorizontalOptions="Start"
        VerticalOptions="Start">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>

        <FlexLayout
            AlignContent="Start"
            AlignItems="Start"
            AlignSelf="Start"
            BackgroundColor="Blue"
            Direction="Row"
            HorizontalOptions="Start"
            JustifyContent="Start"
            VerticalOptions="Start">
            <Label
                BackgroundColor="Red"
                FlexLayout.Basis="100"
                FlexLayout.Grow="0"
                HorizontalOptions="Start"
                HorizontalTextAlignment="Start"
                Text="Content1"
                WidthRequest="100" />
            <Label
                BackgroundColor="Orange"
                FlexLayout.Basis="100"
                FlexLayout.Grow="0"
                HorizontalOptions="Start"
                HorizontalTextAlignment="Start"
                Text="Content2"
                WidthRequest="100" />
        </FlexLayout>
    </Grid>
JasonLooney commented 4 years ago

Can also be reproduced in the official samples (see the Experiment page): https://github.com/xamarin/xamarin-forms-samples/tree/master/UserInterface/FlexLayoutDemos

ChrisTTian667 commented 4 years ago

Same here working with XF4.7, is anybody working on this problem?

xperseguers commented 4 years ago

Same problem but I'm within an AbsoluteLayout, maybe related (https://forums.xamarin.com/discussion/184860/problem-with-a-scrollview-having-a-flexlayout-inside-absolutelayout#latest).

It looks as if the extra height added to my ScrollView is related to the height it would take if the FlexLayout was a simple StackLayout and no wrapping would be done with the content.

I tried as suggested to wrap my FlexLayout into an(other) StackLayout but it does not help.

@nbevans My mobile app will obviously not "resize" (maybe change orientation but I could possibly live with that). Is your hack somehow to be implemented for both iOS and Android somehow? Custom renderer? Mind providing the code?

divyesh008 commented 4 years ago

Same here. I'm temporarily wrapping the FlexLayout inside a StackLayout until this issue is solved.

Yes, exactly, I am facing this issue yet so I have wrapped FlexLayout with StackLayout, and it works fine.

<StackLayout Grid.Row="0" HorizontalOptions="FillAndExpand" Padding="10" VerticalOptions="Start">
    <FlexLayout BackgroundColor="Green" HorizontalOptions="FillAndExpand" VerticalOptions="Start" BindableLayout.ItemsSource="{Binding ItemCollection}"
            Direction="Row" Wrap="Wrap" JustifyContent="Start" AlignContent="Start" Margin="0" Padding="0">
        <BindableLayout.ItemTemplate>
            <DataTemplate>
                <pancake:PancakeView BackgroundColor="Blue"
                    HasShadow="False" IsClippedToBounds="True" Padding="5" Margin="5"
                    CornerRadius="10" HeightRequest="30" HorizontalOptions="Start" VerticalOptions="Start">
                    <Label Text="{Binding Title}" TextColor="White" HorizontalOptions="Center"
                        VerticalOptions="Center" HorizontalTextAlignment="Center"
                        VerticalTextAlignment="Center" />
                </pancake:PancakeView>
            </DataTemplate>
        </BindableLayout.ItemTemplate>
    </FlexLayout>
</StackLayout> 
what3var commented 4 years ago

FYI: Having placed the Flexlayout inside a Stacklayout which is placed inside two nested Grids triggers a NullReferenceException in LayoutSubviews().. Removing the uppermost Grid resolves this.

carbonete commented 3 years ago

Hi, any news? I'm going to forms 5.0 and this problem persist.

thanks

carbonete commented 3 years ago

Same here. I'm temporarily wrapping the FlexLayout inside a StackLayout until this issue is solved.

Yes, exactly, I am facing this issue yet so I have wrapped FlexLayout with StackLayout, and it works fine.

<StackLayout Grid.Row="0" HorizontalOptions="FillAndExpand" Padding="10" VerticalOptions="Start">
    <FlexLayout BackgroundColor="Green" HorizontalOptions="FillAndExpand" VerticalOptions="Start" BindableLayout.ItemsSource="{Binding ItemCollection}"
            Direction="Row" Wrap="Wrap" JustifyContent="Start" AlignContent="Start" Margin="0" Padding="0">
        <BindableLayout.ItemTemplate>
            <DataTemplate>
                <pancake:PancakeView BackgroundColor="Blue"
                    HasShadow="False" IsClippedToBounds="True" Padding="5" Margin="5"
                    CornerRadius="10" HeightRequest="30" HorizontalOptions="Start" VerticalOptions="Start">
                    <Label Text="{Binding Title}" TextColor="White" HorizontalOptions="Center"
                        VerticalOptions="Center" HorizontalTextAlignment="Center"
                        VerticalTextAlignment="Center" />
                </pancake:PancakeView>
            </DataTemplate>
        </BindableLayout.ItemTemplate>
    </FlexLayout>
</StackLayout> 

Thanks this work

mlyrstad commented 3 years ago

Can we please have some feedback on if/when this problem is going to be solved? Since there is no true MinimumWidthRequest, the only option is to wrap buttons (and other things) in FlexLayout to get the desired behavior but having to wrap the flexlayout in a stacklayout means yet another needless layer between...

Some answers on whether this will be fixed would be highly appreciated. Thank you.

to get the desired behavior

Scratch that. This doesn't work either, because the greedy space behavior of FlexLayout goes both ways making this not work either. Back to the drawing board then I guess.

kerberosargos commented 3 years ago

Same issue is for me too. is there any news about that?

azrinsani commented 3 years ago

Hello 2021??? I n my case even wrapping around stack layout doesn't seem to work!!!

Softtinn commented 3 years ago

Any news on this?!

kerberosargos commented 3 years ago

Any update?

kerberosargos commented 3 years ago

We can not use FlexLayout because of this bug. How to solve this issue? Please someone interested in this bug.

kerberosargos commented 3 years ago

I created this (F#) workaround which sort of fixes the issue for me - though it's not perfect, it is bit glitchy when resizing the UWP window.

Something is really wrong with that OnMeasure method in the core implementation of XF.

type FlexLayout_HackFix20190326() =
    inherit FlexLayout()

    override self.OnMeasure(widthConstraint, heightConstraint) =
        let height = self.Children |> Seq.map (fun c -> c.Measure(Double.PositiveInfinity, Double.PositiveInfinity).Request.Height + c.Bounds.Top) |> Seq.maxBy id
        base.OnMeasure(widthConstraint, height)

Hello is there any C# implementation?

kerberosargos commented 3 years ago

@samhouts What is the problem about this bug?

chaoyebugao commented 2 years ago

It's 2021, WILL THIS PROBLEM LAST IN MAUI ?

nbevans commented 2 years ago

@ryanharding Be prepared for same-shit-different-shit in Flutter. Last time I checked it out they were still faffing about trying to make textual word wrap and ellipsis work properly on all platforms.

KevinAnass commented 2 years ago

it works fine to me this my XAML code

data template

<DataTemplate x:Key="templateChartPercent">
        <controllers:ChartPercent
            Title="{helper:Translate PaymentMethode}"
            Margin="7"
            FlexLayout.AlignSelf="Center" />
    </DataTemplate>

FlexLayout

<FlexLayout
                        x:Name="lstChart"
                        BindableLayout.ItemTemplate="{StaticResource templateChartStatic}"
                        Style="{StaticResource FLBase}" />

style

 <Style
            x:Key="FLBase"
            TargetType="FlexLayout">
            <Setter Property="AlignContent" Value="Start" />
            <Setter Property="AlignItems" Value="Start" />
            <Setter Property="Direction" Value="Row" />
            <Setter Property="HorizontalOptions" Value="FillAndExpand" />
            <Setter Property="JustifyContent" Value="SpaceBetween" />
            <Setter Property="VerticalOptions" Value="Start" />
            <Setter Property="Wrap" Value="Wrap" />
        </Style>
nZeus commented 2 years ago

Feb 2022, the issue is still there... Will this ever be fixed? The issue is more than 2years old...

wagenheimer commented 2 years ago

March-2022 nd still no fix? =(

dvPineda commented 2 years ago

Dear diary, it's August 2022 and there aren't any signs of life.

jonathanrandev commented 2 years ago

I worked around this by calling MyGrid .ForceLayout() after the the children were added to the FlexLayout. on MAUI: (MyGrid as IView).InvalidateArrange();