Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

CollectionView height doesn't adapt after height of its content #6554

Open
luczha opened this issue Jun 17, 2019 · 37 comments
Open

CollectionView height doesn't adapt after height of its content #6554

luczha opened this issue Jun 17, 2019 · 37 comments

Comments

@luczha
Copy link

luczha commented Jun 17, 2019

Summary

I was hoping for CollectionView to adapt its height after it's content (When ItemsLayout is set as vertical as it is in default that is). Which just like UICollectionView in native iOS .
Capture

@adrianknight89
Copy link
Contributor

@luczha Can you attach a repro? Also, can you test your code with the latest pre-release?

@LeoJHarris
Copy link

LeoJHarris commented Jun 26, 2019

sampleCollectionView.zip

Below in yellow is a Collectionview with a DataTemplate with a Frame and a nested label, I dont see why this should be stretching that much space vertically. The orientation of the CollectionView is set to horizontal. The way I see it only need the CollectionView to fit the frame and nested label. If this is default behavour then it would be better if the CollectionView would simply fit the content without having to set the HeightRequest (which is my work around).

device-2019-06-27-090345

@karlingen
Copy link

+1 on this

@AnnaShaleva
Copy link

+1

1 similar comment
@sebcsri
Copy link

sebcsri commented Nov 18, 2019

+1

@kcrg
Copy link

kcrg commented Jan 29, 2020

+2

@angusbreno
Copy link

+1

1 similar comment
@ioiooi
Copy link

ioiooi commented Mar 20, 2020

+1

@Huaba93
Copy link

Huaba93 commented Mar 31, 2020

Same problem here. it doesn't even show all entries.

Tried it with BindableLayout and it worked as expected:

<ScrollView Orientation="Horizontal">
    <StackLayout Orientation="Horizontal" Spacing="20" Padding="0,20,0,20"
                 BindableLayout.ItemsSource="{Binding LeaderboardUsers}"
                 BindableLayout.ItemTemplateSelector="{StaticResource RankedUserDataTemplateSelector}" />
</ScrollView>

CollectionView does not work (vertically all items are displayed and height is also ok):

<CollectionView x:Name="LeaderboardCollectionView" ItemsSource="{Binding LeaderboardUsers}"
                ItemTemplate="{StaticResource RankedUserDataTemplateSelector}"
                VerticalOptions="Start" ItemSizingStrategy="MeasureAllItems">
    <CollectionView.ItemsLayout>
        <LinearItemsLayout Orientation="Horizontal" ItemSpacing="20" />
    </CollectionView.ItemsLayout>
</CollectionView>

collectionView

If you need a sample repo let me know.

@ICDevelopments
Copy link

+1

@luczha
Copy link
Author

luczha commented Apr 16, 2020

@samhouts @adrianknight89 Hi ,all .Any update ? Or it would better if there is a workaround . We can implement it by using custom renderer in Android . However , in iOS there is no such a property or API .

@tiagotas
Copy link

+1

@shira164
Copy link

Hi All, Any update?

@lomdar67
Copy link

+1

1 similar comment
@tscholze
Copy link

+1

@abhi-shukla
Copy link

+1

@eli191
Copy link

eli191 commented May 17, 2020

A simple solution is to calculate the height and set it with a MVVM auto-updating parameter.

@tscholze
Copy link

@eli191 do you have any small sample? :)

@eli191
Copy link

eli191 commented May 17, 2020

@tscholze I am doing it through ReactiveUI so it won't help, but basically you will add
HeightRequest="{Binding CustomColViewHeight}" in the xaml
And in your ViewModel, have that property CustomColViewHeight implementing INPC.

@lorant-csonka-ICE
Copy link

+1

2 similar comments
@Alextorres950325
Copy link

+1

@mohsen-mohamed
Copy link

+1

@vanyok1991
Copy link

any update here? have similar issue

@softlion
Copy link
Contributor

softlion commented Sep 1, 2020

This is not an issue. This is by design.
A CollectionView is a ScrollView.
And a ScrollView does not autosize depending of its content. Instead it scrolls its content when this content is larger than the scroll's viewport (width or height).

So if you still want to autoheight a ScrollView, sum the height of each element and each separator, and set the HeightRequest of the CollectionView to this value. At runtime.
Maybe someone have created a behavior for this already: yourcollection.HeightRequest = yourcollection.ContentSize.Height;

@Tommigun1980
Copy link

Tommigun1980 commented Nov 24, 2020

This is not an issue. This is by design.
A CollectionView is a ScrollView.
And a ScrollView does not autosize depending of its content. Instead it scrolls its content when this content is larger than the scroll's viewport (width or height).

So if you still want to autoheight a ScrollView, sum the height of each element and each separator, and set the HeightRequest of the CollectionView to this value. At runtime.
Maybe someone have created a behavior for this already: yourcollection.HeightRequest = yourcollection.ContentSize.Height;

There really should be a property that can be turned on for when this behaviour is desired.
One use case is for example when you have multiple expanders on top of each other showing different collection view data.
I resorted to converting these back to bindable layouts for now.

It gets really unwieldy setting the height manually with collections that can change as you will have to add all kinds of listeners in code for something that should imho be built into the component.

@softlion
Copy link
Contributor

softlion commented Nov 24, 2020

@Tommigun1980 both iOS and Android uses optimized virtual lists which includes fast scrolling with acceleration. To be able to do that, they don't compute the height of each item as this would require a full layout of each item view, plus a binding of each item view with its datamodel (as you know, those virtual lists keep only about 10 views - they don't create a view for each item).

Instead they suppose each item has a certain height (which you can give). This height is mainly used for displaying the scroll handle on the right while scrolling, and detect the end of the list is to stop scrolling smoothly.

As Android does support dynamic height change of visible items, iOS does not. On iOS the correct way to do this is to remove/add the item again in a "transaction" so it can smoothly animate the change. But transactions are not available on out-of-the-box ObservableCollections on .NET ... even on .NET 5. And of course is not implemented in the backed Items container on iOS in Xamarin Forms.

Well that i not exactly true. Xamarin Forms iOS does implement a fake transaction by buffering changes happening on the same thread. When the main thread is free, it applies the changes.

@Tommigun1980
Copy link

@Tommigun1980 both iOS and Android uses optimized virtual lists which includes fast scrolling with acceleration. To be able to do that, they don't compute the height of each item as this would require a full layout of each item view, plus a binding of each item view with its datamodel (as you know, those virtual lists keep only about 10 views - they don't create a view for each item).

Instead they suppose each item has a certain height (which you can give). This height is mainly used for displaying the scroll handle on the right while scrolling, and detect the end of the list is to stop scrolling smoothly.

As Android does support dynamic height change of visible items, iOS does not. On iOS the correct way to do this is to remove/add the item again in a "transaction" so it can smoothly animate the change. But transactions are not available on out-of-the-box ObservableCollections on .NET ... even on .NET 5. And of course is not implemented in the backed Items container on iOS in Xamarin Forms.

Well that i not exactly true. Xamarin Forms iOS does implement a fake transaction by buffering changes happening on the same thread. When the main thread is free, it applies the changes.

When the measurement strategy is MeasureFirstItem I don't see why it couldn't be done, as it'd be analogous to a BindableLayout (with virtualisation support). It'd just be 'items * firstItemHeight'. It's such a common use case that I'd love it if it was supported.

PS. I deleted my previous reply to you as I thought I was in a different bug report so my context was incorrect.

@neville-nazerane
Copy link

Has anyone created a behavior for this yet?

@sact1909
Copy link

Something new with this issue?

@jerryhuang-net
Copy link

In my case, this happens on CollectionView and ListView on iOS only (so far), and even on iOS, it only happens on physical device. So below is how I worked-around the issue:

private double width = 0;
private double height = 0;
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height);
try
{
if (this.width != width || this.height != height)
{
this.width = width;
this.height = height;
//reconfigure layout
if (this.height > 0 &&
Device.RuntimePlatform == Device.iOS)
view.HeightRequest = this.Height - 50;
}

        }
        catch (Exception ex)
        {
            vm.ErrorHandling(ex);
        }
    }

In this scenario, I know what is the height of the collection view should be, so deduct a value from the screen height does the trick. A little nasty, but works for me...

@sact1909
Copy link

can you share a project in xamarin form on how to implement your solution @jerryhuang-net

@vgnbk
Copy link

vgnbk commented Apr 28, 2021

Faced with the same issue and find this.
In Workaround area there is a solution of this problem:
Just replase <LinearItemsLayout> with <GridItemsLayout> inside CollectionView.ItemsLayout.

<CollectionView.ItemsLayout>
    <GridItemsLayout  
       HorizontalItemSpacing="10" 
       Orientation="Horizontal"
       SnapPointsType="MandatorySingle"
       SnapPointsAlignment="End"/>
</CollectionView.ItemsLayout>

After this change items inside CollectionView started to display correctly.
Hope this will be helpfull.

@kenchan97
Copy link

+1

1 similar comment
@3dfxuser
Copy link

3dfxuser commented Jun 2, 2021

+1

@Syed-Esqimo
Copy link

Faced with the same issue and find this.
In Workaround area there is a solution of this problem:
Just replase <LinearItemsLayout> with <GridItemsLayout> inside CollectionView.ItemsLayout.

<CollectionView.ItemsLayout>
    <GridItemsLayout  
       HorizontalItemSpacing="10" 
       Orientation="Horizontal"
       SnapPointsType="MandatorySingle"
       SnapPointsAlignment="End"/>
</CollectionView.ItemsLayout>

After this change items inside CollectionView started to display correctly.
Hope this will be helpfull.

I can confirm the above worked for me on a slighlty different context. In my case, I was setting Grid.RowHeight to 0 and back to original height and CollectionView with LinearLayout wasnt expanding back to its original height.

@paul-charlton
Copy link

I've had success with this (from https://stackoverflow.com/questions/68440238/how-to-set-auto-height-of-collection-view-in-xamarin-forms)

public class CollectionFitContentBehavior : Behavior<CollectionView>
{
    List<View> _itemsView;
    CollectionView _control;
    protected override void OnAttachedTo(CollectionView bindable)
    {
        base.OnAttachedTo(bindable);
        _control = bindable;
        _control.ChildAdded += ChildsAdded;
        _itemsView = new List<View>();
    }

    protected override void OnDetachingFrom(CollectionView bindable)
    {
        base.OnDetachingFrom(bindable);
        _control.ChildAdded -= ChildsAdded;

        foreach(var item in _itemsView)
            item.SizeChanged -= ChildSize;
    }

    private void ChildsAdded(object sender, ElementEventArgs e)
    {
        var cell = (e.Element as View);
        cell.SizeChanged += ChildSize;
        _itemsView.Add(cell);
    }

    private void ChildSize(object sender, EventArgs e)
    {
        var cell = (sender as View);
        _control.HeightRequest = _control.HeightRequest + cell.Height;
    }
}

@AlasaliCS
Copy link

AlasaliCS commented Feb 19, 2023

I used VerticalOptions="FillAndExpand" for the entire "DataTemplate" and it is working for me.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests