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.87k forks source link

[Bug] CollectionView takes too much space/expands vertically #6451

Open toomasz opened 5 years ago

toomasz commented 5 years ago

Description

CollectionView, when places with other controls in for example stackLayout, takes too much space vertically. It should only take as much space as total items height(at least when VerticalOptions="Start" are set)

Steps to Reproduce

  1. Run sample

Expected Behavior

CollectionView should only take as much space as sum of it's items

Actual Behavior

CollectionView expads to higher height or takes all space available

Basic Information

Screenshots

UWP: obraz

Android: Screenshot_20190607-165555 (1)

Reproduction Link

CollectionViewRepro.zip

samhouts commented 5 years ago

Duplicate of #5763

toomasz commented 5 years ago

@samhouts I see its similar to other issue but:

The CollectionView is meant to expand to its available vertical space.

Why is that? I think it should have option not to expand to all available vertical space, like most controls. It's very common use case, lets say I want to have two lists, one below other and some buttons between them. Without this option it's impossible. Or is there some way?

hartez commented 5 years ago

@samhouts #5763 is a FlexLayout issue.

Also, the current layout behavior of CollectionView is basically the same as what ListView does (always maximally expanding, no matter what the layout options are); we may want to reconsider this for CollectionView. I'd like to reopen this one, at least for now.

(I'm not saying we will change it - just that I'd like to think about it some more.)

MeikandaNayanar commented 5 years ago

I saw this bug report is closed and hence I created a new one few hours ago with my real use case explaining the same issue

Tragetaschen commented 5 years ago

Is there any workaround to tame a CollectionView's vertical extent?

toomasz commented 5 years ago

@Tragetaschen I haven't found one but maybe I'm missing something. @hartez could you advice on how to stop collection view expanding vertically? Is it possible currently?

Tragetaschen commented 5 years ago

I have the CollectionView in a ScrollView+StackLayout.

When the item template has fixed size (i.e. you can use ItemSizingStrategy="MeasureFirstItem"), I have successfully bound HeightRequest to the same object as the ItemsSource with an IValueConverter that basically does

n * itemTemplateHeight 
+ (n-1) * itemSpacing 
+ ε // 1, 2 or something else to accomodate for internal rounding errors
HobDev commented 4 years ago

I able to control the height of CollectionView using AbsoluteLayout.

EvoPulseGaming commented 4 years ago

CollectionView should only take up the space needed to display the items, if we want to take up the entire screen we would specify this as we do with everything else.

MitchBomcanhao commented 4 years ago

having a collection view that only takes the necessary space is a must for me. I would like to replace some hacky flexlayouts with collectionviews, but the spurious space it adds to the layout makes it useless.

Alex-111 commented 4 years ago

Please at least add an option for the user to control the layout. There are plenty of users out there who need this feature! At least there is a chance to correct this in the new collectionview control!

garyng commented 4 years ago

If nothing CollectionView-specific features are used, you can get around this by binding to BindableLayout on StackLayout.

TheCodeSage commented 4 years ago

This seems like something that should exist with collection view seeing as you can create a horizontal collection and set the ItemSizingStrategy="MeasureAllItems". I would think the vertical height of the collection view would only be as high as each item. So if a collection view which scrolls horizontally exists at the bottom of a page, it is only taking up the space of the items in view, but instead it just takes over the whole page.

idchlife commented 4 years ago

So basically the only easy way is to hardcode HeightRequest in CollectionView element?

tomeverin commented 4 years ago

I'm doing similar to what @Tragetaschen suggested. Works fine. However not very elegant and would be ideal if VerticalOptions="Start" would work as expected.

Pentadome commented 4 years ago

Any work around? why is this still bugged?

pspeybro commented 4 years ago

I would also like to see CollectionView respect the verticalOptions="start". In my case it is a horizontal CollectionView in a stacklayout in a scrollview and the stacklayout seems to take the height of the screen, even though there is only a limited height needed.

A workaround would also be appreciated while awaiting a fix.

Keflon commented 4 years ago

The following CollectionView is in an Auto row and displays a narrow horizontally scrolling collection of strings. The required height is minimal. The height of the CollectionView fills the screen on my Nexus 5 phone. If that's expected behaviour so be it, but it doesn't make much sense to me.

<CollectionView Grid.Row="3" ItemsSource="{Binding Categories}" ItemsLayout="HorizontalList" VerticalOptions="Start">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <Label Text="{Binding Text}"/>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

HugeCollectionView

Xamarin rocks! Here seems as good a place as any to say thank you and keep up the good work! :)

Inrego commented 4 years ago

I too am really looking forward to a change on how this works. Why would a horizontal list take up full height of a page? Also if used for showing just a few items vertically, you can't show anything below it, without the user having to scroll almost a full empty page.

Basically, CollectionView is currently designed with the assumption that it will be the only view on a page. That just doesn't hold true for real-life apps.

Inrego commented 4 years ago

Until then, I guess the "workaround" is to use StackLayout with BindableLayout instead of CollectionView. That just has terrible performance on longer lists, so it's not a great solution either.

pspeybro commented 4 years ago

Until then, I guess the "workaround" is to use StackLayout with BindableLayout instead of CollectionView. That just has terrible performance on longer lists, so it's not a great solution either.

Inrego, one way to work around it is to wrap a StackLayout (for example) around the Collectionview and bind the HeightRequest of the StackLayout to a property in the viewmodel that calculates the required height based on some things (contents of the CollectionView items).

Not ideal but it worked in my case.

Inrego commented 4 years ago

Until then, I guess the "workaround" is to use StackLayout with BindableLayout instead of CollectionView. That just has terrible performance on longer lists, so it's not a great solution either.

Inrego, one way to work around it is to wrap a StackLayout (for example) around the Collectionview and bind the HeightRequest of the StackLayout to a property in the viewmodel that calculates the required height based on some things (contents of the CollectionView items).

Not ideal but it worked in my case.

I'm just speculating, but calculating the height of each item would also yield not so good performance on large lists. Of course, this is only a problem when the list is smaller than the page, so I could do the calculation only if there's not enough items to fill the page.

But then again, looks like it might be solved soon. And it'll be a while before my app hits production. So I can live with the bad performance of StackLayout until then I think.

But still good to have the options here for others to see.

AmrAlSayed0 commented 4 years ago

@pspeybro How would you go about calculating the height of the displayed items? If I have set a fixed height on the template then maybe I can use that, but what if it is not? Is there a way to access the displayed views so I can write a behavior (maybe?) that can adjust the height when the ItemSource changes?

pspeybro commented 4 years ago

@pspeybro How would you go about calculating the height of the displayed items? If I have set a fixed height on the template then maybe I can use that, but what if it is not? Is there a way to access the displayed views so I can write a behavior (maybe?) that can adjust the height when the ItemSource changes?

@AmrAlSayed0 , in my case, I was adding extra rows (users) in vertical stacklayout that was inside de collectionview DataTemplate (while collectionview has horizontal orientation). A user can click something to add an extra user. In my viewmodel, when an extra row is added, I also trigger the OnPropertyChanged of a Height property that calculates the required height, based on the number of users. This Height property is bound to the HeightRequest of a Stacklayout that contains the horizontal collectionview.

Not very pretty, but it works for me...

ndastur commented 3 years ago

Any news on this. Starting using the collectionview and hit upon this almonst straight away. Then found this more than year old bug issue. It really doesn't make much sense from a layout POV to expand like this

Nerves82 commented 3 years ago

This is a +1,000 for me. It seems insane that the collection view is so single use. I can't do something so simple as have a label under my list be cause the list (even if it only has a fe items in it) is huge! It makes the collection view nearly worthless. This needs to be fixed!

Johanna-Victoria commented 3 years ago

Every component containing HorizontalOptions and VerticalOption should expand and fill according to value set. It doesn't make sense that a component is overriding these values. I would really like to see that the properties remains for CollectionView and the components size can be adjusted by the size of the collection.

AmSmart commented 3 years ago

This feature is very important and it should be given high priority

elielson-anjos commented 3 years ago

Any news on this?

Just tried to do a very simple horizontal collections view to display some tags, and the entire thing expands vertically to the whole screen eventhough I set VerticalOptions="Center" and the elements inside the collection view is not above 10 units high and I set the ItemsLayout to "HorizontalList".

Why?

May be the logic behind this behaviour is that listviews expand horizontally and they thought the same would apply to horizontal lists(expanding vertically)...?

I had to set the height of the entire collection using the "HeigthRequest" property, for my use case this will sufice, but what If I had itens with dinamic height?

PS:I would like to take this oportunity to say that Xamarin Forms is awesome!!!

dpuckett commented 3 years ago

Sorry but, why make the assumption that ANY control view should be taking up the entire screen space as "expected behaviour"??? Isn't this why we have Vertical/Horizontal Options properties on our views, so we can specify we WANT this behaviour?

This isn't only true of the CollectionView, but ListView as well!

@samhouts is there any movement on this bug being fixed soon? I would really like to use CollectionView for performance over StackLayout as it's having an impact on my users experience.

jomalbert1594 commented 3 years ago

Use grid and set the row height to "*", put the CollectionView to that row and set its HeightRequest to 0. The CollectionView will consume the size of the grid's row.

elielson-anjos commented 3 years ago

Use grid and set the row height to "*", put the CollectionView to that row and set its HeightRequest to 0. The CollectionView will consume the size of the grid's row.

Unfortunately, it didn't work for me.

AmSmart commented 3 years ago

@Rothanan Are you sure you implemented it correctly? It seems quite impossible for a view to expand past the bounds of its parent. Or did the CollectionView stretch the height of the Grid?

jomalbert1594 commented 3 years ago

@Rothanan Sorry for the very late reply, I set the HeightRequest = 0 at the .cs of the view where the CollectionView was declared. Try to rerun the app, sometimes the code does not reflect immediately, idk why..

xamiell commented 3 years ago

Same here

nykkel commented 3 years ago

Instead of

<CollectionView ItemsSource="{Binding Categories}">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <Label Text="{Binding Text}"/>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

..write..

<StackLayout BindableLayout.ItemsSource="{Binding Categories}" >
         <BindableLayout.ItemTemplate>
            <DataTemplate>
                  <Label Text="{Binding Text}"/>
           </DataTemplate>
    </BindableLayout.ItemTemplate>
</StackLayout>

.. and Bob's your uncle!

Inrego commented 3 years ago

Instead of

<CollectionView ItemsSource="{Binding Categories}">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <Label Text="{Binding Text}"/>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

..write..

<StackLayout BindableLayout.ItemsSource="{Binding Categories}" >
         <BindableLayout.ItemTemplate>
            <DataTemplate>
                  <Label Text="{Binding Text}"/>
           </DataTemplate>
    </BindableLayout.ItemTemplate>
</StackLayout>

.. and Bob's your uncle!

Yeah.. if you don't want any of the benefits of CollectionView like smooth scrolling and reused elements or any of the other features of CollectionView. Then sure, by all means - use something else than CollectionView.

victorest03 commented 3 years ago

As an alternative to what @nykkel mentions, we can cover the CollectionView in a StackLayout instead of a FlexLayout. The CollectionView will push the next element to the end of the layout.

Before

<FlexLayout
        BackgroundColor="Blue"
        Direction="Column">
        <RefreshView>
            <CollectionView
                BackgroundColor="Yellow">
                <CollectionView.ItemTemplate>
                    <DataTemplate>
            ...
                    </DataTemplate>
                </CollectionView.ItemTemplate>
                <CollectionView.EmptyView>
                    ...
                </CollectionView.EmptyView>
            </CollectionView>
        </RefreshView>
        <StackLayout BackgroundColor="Beige">
            ...
        </StackLayout>
    </FlexLayout>

image

After

<StackLayout Spacing="0" BackgroundColor="Blue">
        <RefreshView>
            <CollectionView
                BackgroundColor="Yellow" >
                <CollectionView.ItemTemplate>
                    <DataTemplate>
            ...
                    </DataTemplate>
                </CollectionView.ItemTemplate>
                <CollectionView.EmptyView>
                    ...
                </CollectionView.EmptyView>
            </CollectionView>
        </RefreshView>
        <StackLayout BackgroundColor="Beige">
            ...
        </StackLayout>
    </StackLayout>

image

Kalyxt commented 1 year ago

So who is gonna do it ? Who is gonna fix it, or is this expected behavior ?

bazsisz commented 1 year ago

In case of a horizontal collectionView, wrapping the collectionview to a stackLayout would solve the problem in my opinion. Something like this:

<StackLayout>
   <CollectionView ItemsSource="{Binding TabItems, Mode=OneWay}">
   <CollectionView.ItemsLayout>
      <GridItemsLayout Orientation="Vertical"
                                     Span="3"/>
   </CollectionView.ItemsLayout>
       <CollectionView.ItemTemplate>
             <DataTemplate>
                    <!--Content-->
             </DataTemplate>
        </CollectionView.ItemTemplate>
   </CollectionView>
</StackLayout>

Let me know what you think or if you have better workarounds.

elizeon commented 1 year ago

+1 For fix please. This issue is frustrating. I'm trying to have achieve several lists in a single page, either with the whole page being scrollable or each list view being scrollable. I couldn't figure out why the listview was behaving differently to other components.

janseris commented 1 year ago

This is still an issue with .NET MAUI as well when CollectionView is inside RefreshView.