Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[iOS] Xamarin.Forms Listview Row Height Does Not Update When Changing Content Size (such as label) #2383

Open
3 tasks
samhouts opened this issue Apr 7, 2018 · 34 comments

Comments

@samhouts
Copy link
Task lists! Give feedback
Member

@samhouts samhouts commented Apr 7, 2018

Description

Migrated from https://bugzilla.xamarin.com/show_bug.cgi?id=44525.

Issue is resolved in RecycleElement mode, but not in RetainElement mode and other scenarios.

Test case is in Control Gallery, but it needs to be updated with other CachingStrategies and new info in Bugzilla ticket.

  • Missing Preserve attribute
  • Test needs to be automated
  • Manual test needs instructions

Steps to Reproduce

1.) There is no need for a custom cell at all as it doesn't do anything
2.) Bug: If set to RetainElement the new text is shown, but the image is not resized at all until you scroll down and scroll back up it is resized correct.
3.) Bug: if set to it to RecycleElement then it doesn't resize at first and you can't see the rest of the text, but as soon as you scroll down and up it is resized correct.
4. Bug: scrolling up and down becomes jittery, cells overlap.

Basic Information

  • Version with issue: 2.5.0+ (last tested with 3.3.0.967583)
  • Last known good version:

Issue2383.zip

@pauldipietro pauldipietro added this to New in Triage Apr 7, 2018
@jassmith jassmith moved this from New to Ready For Work in Triage Apr 7, 2018
@LeeCenY
Copy link

@LeeCenY LeeCenY commented Apr 27, 2018

Hidden controls also do not update height!

If a control of the Item inside the ListView is hidden, Android will automatically adjust the height of the UI Item, but iOS will not automatically adjust the height

@aabc123
Copy link

@aabc123 aabc123 commented Aug 22, 2018

Does anyone have a work-around for this issue on iOS? I'm hitting this now also. We have some labels which we should when the item is selected so need the view cell to automatically expand when they are shown.

@LJordanCoCo
Copy link

@LJordanCoCo LJordanCoCo commented Aug 24, 2018

Just hit this on 3.1.0.697729 and it is really apparent on the 5s and SE . I have a label that wraps up to three lines in a listview. When I first land on the screen, the first line of text is cut off for almost my entire list of items and a ton of items are crammed into the top of the list (at a rate of 1/2 label height per item, since they're cut off). Once I scroll down, any item that goes off screen will come back on screen with whatever size of row they were replaced with. For instance, if the first item in my list should take three rows of text, it gets cut off halfway through the first line. I then scroll down, and the item that replaces it takes two lines of text. When I scroll back up, the first item has two lines' worth of space, even if it should have three.

I had 2.4.0.282 before (long story) and this was not happening at all. Maybe referencing the logic from that release will help?

Side note: Pull to refresh makes them all look correct.

One more note: This seems to be happening if the data is present before the screen first appears (say, in a multi-tab view). If I delay the data binding until after the screen is visible, this goes away.

@LJordanCoCo
Copy link

@LJordanCoCo LJordanCoCo commented Sep 5, 2018

Another note related to my last post: Even when I manage to get the screen to look right on first load, changing orientation breaks it again.

More data related to my as-yet-unsuccessful troubleshooting attempts:

Given a listview that has a custom control (no custom renderers) as the data template
AND the custom control's top-level element has a specific HeightRequest
AND HasUnevenRows=true
THEN the listview renders all rows at exactly that HeightRequest, regardless of content.

Given the above, but with MinHeightRequest, the rows are collapsed in on themselves.
Given the above, but with neither MHR or HR, the rows are collapsed in on themselves.

If I set the height of the custom control's top-level Element (in this case a grid) to a specific HeightRequest, then the listview, despite HasUnevenRows=true, will render every single row with that height, regardless of content.

Whereas if I leave that off, or try using MinimumHeightRequest=x, the issue remains.

@LJordanCoCo
Copy link

@LJordanCoCo LJordanCoCo commented Sep 5, 2018

I also want to add that this is happening for me regardless of mode: RecycleElement, RecycleElementAndDataTemplate, and RetainElement all behave in this way, except with Retain it never resizes anything ever, and the sizes are just terrible.

@swasti29
Copy link

@swasti29 swasti29 commented Sep 10, 2018

Any one find the solution of it?

@adrianknight89
Copy link
Contributor

@adrianknight89 adrianknight89 commented Sep 22, 2018

@jassmith @samhouts I'm wondering what your timeframe is for fixing high impact issues. Some of the reported ones go as far back as Dec 2017.

@samhouts samhouts added this to To do in iOS Ready For Work Oct 15, 2018
@samhouts samhouts removed this from Ready For Work in Triage Oct 15, 2018
@samhouts samhouts added the i/high label Nov 2, 2018
@ederbond
Copy link
Contributor

@ederbond ederbond commented Nov 6, 2018

Any time frame to fix this blocking issue ?

@LucasJordan
Copy link

@LucasJordan LucasJordan commented Nov 6, 2018

I found that if I don't use a custom control resizing works. By that I mean if I take my XAML from within the custom control and move it to the ViewCell in the DataTemplate directly (plus fixing bindings), sizing seems to be fine.

For example, if I have a control that is a grid with stuff in it I can adjust the XAML as below.

Broken
<DataTemplate><ViewCell><alias:control … /></ViewCell></DataTemplate>

Works:
<DataTemplate><ViewCell><Grid>...</Grid></ViewCell></DataTemplate>

Hopefully this workaround saves someone out there some sanity while we wait.

@ernestoyaquello
Copy link

@ernestoyaquello ernestoyaquello commented Dec 4, 2018

@LucasJordan, my custom control is already inside a ContentView and yet this bug is occurring in my app.

Honestly, at this point I just cannot believe that we are already in the version 3.x of this framework (with the version 4.0 about to be released) and something as basic as creating a list with uneven rows is still misbehaving and causing issues. Plus, this is a blocking bug labeled as "high impact", but after several months we still have no solution for it.

Sorry for the rant, but this problem is just driving me crazy. I really hope we can get either a solution or a functioning workaround soon.

@ghost
Copy link

@ghost ghost commented Dec 6, 2018

@LucasJordan, my custom control is already inside a ContentView and yet this bug is occurring in my app.

Honestly, at this point I just cannot believe that we are already in the version 3.x of this framework (with the version 4.0 about to be released) and something as basic as creating a list with uneven rows is still misbehaving and causing issues. Plus, this is a blocking bug labeled as "high impact", but after several months we still have no solution for it.

Sorry for the rant, but this problem is just driving me crazy. I really hope we can get either a solution or a functioning workaround soon.

It's open source - they don't turn down PRs - if in dire need you can always post a PR. With any open source library comes the understanding that if I really need something either I need to code it myself or wait for a fix. It's why for really complex apps or apps that require UI to just work we code Xamarin Native/Classic and only for smaller apps do we use Forms.

@ernestoyaquello
Copy link

@ernestoyaquello ernestoyaquello commented Dec 6, 2018

@LucasJordan, my custom control is already inside a ContentView and yet this bug is occurring in my app.

Honestly, at this point I just cannot believe that we are already in the version 3.x of this framework (with the version 4.0 about to be released) and something as basic as creating a list with uneven rows is still misbehaving and causing issues. Plus, this is a blocking bug labeled as "high impact", but after several months we still have no solution for it.

Sorry for the rant, but this problem is just driving me crazy. I really hope we can get either a solution or a functioning workaround soon.

It's open source - they don't turn down PRs - if in dire need you can always post a PR. With any open source library comes the understanding that if I really need something either I need to code it myself or wait for a fix. It's why for really complex apps or apps that require UI to just work we code Xamarin Native/Classic and only for smaller apps do we use Forms.

Yeah, it looks like choosing Xamarin Forms for a complex app isn't the best idea...

The thing is that, while I understand that this is just an open source library like any other, I still expect it to meet certain standards, mostly because it is officially backed up by Microsoft and because it has been out there for a while, which means that by now it should be fairly stable (at the very least, I would expect the basic functionality of creating lists to work without major issues).

Anyway, sorry again for the rant; let's just focus on discussing only about the original issue to keep the comment section clean.

@ernestoyaquello
Copy link

@ernestoyaquello ernestoyaquello commented Dec 6, 2018

I managed to implement a workaround that fixed the issue in my case, so I will explain here what I did just in case it is of any help.

Initially, I had a list in which each element was a custom view:

...
<ListView
    HasUnevenRows="true"
    ItemsSource="{Binding MyItemsSource}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <alias:MyCustomView
                    Data="{Binding MyData}"/>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>
...

And this custom view had some bindings on it:

<ContentView 
    xmlns="http://xamarin.com/schemas/2014/forms" 
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="MyNamespace.MyCustomView"
    x:Name="this">
    <Label
        Text="{Binding Data, Source={x:Reference this}}" />
</ContentView>
public partial class MyCustomView : ContentView
{
    public static readonly BindableProperty DataProperty = 
        BindableProperty.Create(
            nameof(Data), 
            typeof(string), 
            typeof(MyCustomView), 
            null);
            
    public string Data
    {
        get => (string)GetValue(DataProperty);
        set => SetValue(DataProperty, value);
    }        

    public MyCustomView()
    {
        InitializeComponent();
    }
}

My initial goal was to measure the height of the view MyCustomView as soon as it was given a binding context, just so I could set the height of the cell with the measured height of the view. However, I saw that the measurement that I was obtaining inside OnBindingContextChanged() after calling Measure() was always wrong.

I did some debugging and I realised that, even though the property Data had already been set in the view MyCustomView at the time when I was trying to get the measurement, the text of the label contained within the custom view was still empty, which I understand was happening because the bindings couldn't propagate fast enough to the inner elements. This made me realise that my issue was occurring because Xamarin Forms was measuring the height of my custom view before all its elements were updated, which was causing the measurement to be wrong.

To work around this, I decided to replace all the bindings with assignations, just like this:

<ContentView 
    xmlns="http://xamarin.com/schemas/2014/forms" 
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="MyNamespace.MyCustomView"
    x:Name="this">
    <!-- No binding here; the value will be set on code -->
    <Label
        x:Name="MyLabel" />
</ContentView>
public partial class MyCustomView : ContentView
{
    public static readonly BindableProperty DataProperty = 
        BindableProperty.Create(
            nameof(Data), 
            typeof(string), 
            typeof(MyCustomView), 
            null,
            propertyChanged: OnDataChanged);

    public string Data
    {
        get => (string)GetValue(DataProperty);
        set => SetValue(DataProperty, value);
    }        

    public MyCustomView()
    {
        InitializeComponent();
    }

    private static void OnDataChanged(BindableObject bindable, object oldvalue, object newvalue)
    {
        if (bindable is MyCustomView myCustomView)
        {
            // Setting the text of this element manually instead of using bindings
            myCustomView.MyLabel.Text = myCustomView.Data;
        }
    }
}

And voilà! The list was finally working smoothly and without problems. Of course, this implementation is not ideal, as you have to take care of updating all the elements manually, but it is still better than a list that doesn't display the rows correctly.

TL;DR: I replaced all the bindings of my custom view with manual assignations and the list started working properly.

@samhouts samhouts added this to To do in Sprint 146 Dec 15, 2018
@vlkam
Copy link

@vlkam vlkam commented Dec 31, 2018

I've worked around this with cell.ForceUpdateSize()

@samhouts samhouts moved this from To do to Returned to backlog in Sprint 146 Jan 9, 2019
@hagronnestad
Copy link

@hagronnestad hagronnestad commented Mar 18, 2019

There's still an issue with updating the cell height when doing changes in the DataTemplate. I have a button that is only visible when a cell is selected. When I select the cell, the height doesn't change to fit the new contents on iOS. It works perfectly on Android.

Xamarin.Forms version: 3.6.0.220655

Relevant ListView properties:

HasUnevenRows="True"
CachingStrategy="RecycleElement"
RowHeight="-1"

Screenshot iOS:
image

Screenshot Android:
image

@thisdarktao
Copy link

@thisdarktao thisdarktao commented Mar 26, 2019

As others have mentioned, we have tried cell.ForceUpdateSize() but this causes the list scroll height to jump around as the cells themselves force a resize. We have a custom HTML renderer inside a cell and this causes the content to be clipped.

@samhouts Is there any movement on this issue getting resolved?

@samhouts
Copy link
Member Author

@samhouts samhouts commented Apr 18, 2019

Unfortunately, there is no progress on this issue yet. However, we can confirm that the CollectionView will not suffer from this problem and will not require ForceUpdateSize!

@ianvink
Copy link

@ianvink ianvink commented May 8, 2019

A work around that has worked well for me is to invert and back the HasUnevenRows. This forces a clean cell update that ForceUpdateSize doesn't have. ForceUpdateSize can cause some controls in a cell to not get set.

Inside a ViewCell:

            if (this.Parent is ListView list)
            {
                list.HasUnevenRows = !list.HasUnevenRows;
                list.HasUnevenRows = !list.HasUnevenRows;
            }
@sonic1015
Copy link

@sonic1015 sonic1015 commented Jul 23, 2019

This fix no longer works, at least with Xamarin.Forms 4.1. Observed that HasUnevenRows just stays false, and never switches back to false. ForceUpdateSize Works on Android, but redraws the whole list on iOS and eventually freezes the whole app.

@bnSonic
Copy link

@bnSonic bnSonic commented Aug 10, 2019

I'm currently running into this problem :/
Here the results of a small test:

The ListView:

<ListView IsGroupingEnabled="true"
                      HasUnevenRows="true"
                      ItemsSource="{Binding BudgetGroupList}"
                      ItemSelected="Handle_ItemSelected"
                      ItemTapped="Handle_ItemTapped"
                      ItemTemplate="{StaticResource BudgetTemplateSelector}"
                      GroupHeaderTemplate="{StaticResource BudgetTemplateSelector}"
                      CachingStrategy="RetainElement"
                      x:Name="listViewBudget"
                        >

The XAML of the ViewCell – This is the version that doesn't resize correctly:
As you can see it is a ViewCell that holds a Grid with an Autosize row and three columns.
A StackLayout with a Label is put inside the first column. Problem occurs if Text is longer and Word Wrap kicks in

Some Rows are resized correctly, some are not

<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms" 
          xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
          x:Class="TIMB.Pages.Budget.ViewCells.TestCell"
          BindingContextChanged="Handle_BindingContextChanged"
          >
    <ViewCell.View>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="2*" />
                <ColumnDefinition Width="1*" />
                <ColumnDefinition Width="1*" />
            </Grid.ColumnDefinitions>
            <StackLayout Grid.Row="0" Grid.Column="0"
                         Padding="10"
                         VerticalOptions="CenterAndExpand">
                <Label Grid.Row="0" Grid.Column="0"
                    x:Name="labBezeichnung"
                               Text="{Binding KategorieBezeichnung, FallbackValue='Bezeichnung die etwas länger ist'}"
                               FontSize="Large"
                               />
            </StackLayout>
        </Grid>
    </ViewCell.View>
</ViewCell>

Now, if i skip the StackLayout and put the Label directly into the Grid row - it works correctly:

<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms" 
          xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
          x:Class="TIMB.Pages.Budget.ViewCells.TestCell"
          BindingContextChanged="Handle_BindingContextChanged"
          >
    <ViewCell.View>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="2*" />
                <ColumnDefinition Width="1*" />
                <ColumnDefinition Width="1*" />
            </Grid.ColumnDefinitions>
            <!--<StackLayout Grid.Row="0" Grid.Column="0"
                         Padding="10"
                         VerticalOptions="CenterAndExpand">-->
                <Label Grid.Row="0" Grid.Column="0"
                    x:Name="labBezeichnung"
                               Text="{Binding KategorieBezeichnung, FallbackValue='Bezeichnung die etwas länger ist'}"
                               FontSize="Large"
                               />
            <!--</StackLayout>-->
        </Grid>
    </ViewCell.View>
</ViewCell>

It breaks again if i put some Custom Controls inside the other columns - These controls again are build with a Grid / Frame / StackLayout Combination like:

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="TIMB.Controls.EditLabel"
             >
    <ContentView.Content>
        <Grid>
            <Frame BackgroundColor="#b3f5b4"
                   x:Name="theFrame"
                   Padding="10,0,10,0"
                   HeightRequest="20"
                   CornerRadius="15"
                   HasShadow="false"
                   VerticalOptions="CenterAndExpand"
                   HorizontalOptions="FillAndExpand">
                <StackLayout Orientation="Horizontal"
                             HorizontalOptions="FillAndExpand">
                    <Label x:Name="labText" 
                           Text="(Wert)"
                           VerticalOptions="Center"
                           VerticalTextAlignment="Center"
                           HorizontalOptions="FillAndExpand"
                           HorizontalTextAlignment="End">
                    </Label>
                </StackLayout>
           </Frame>
        </Grid>
    </ContentView.Content>
</ContentView>

Again - if i comment out the Grid and the StackLayout, it works again… of course this is not a solution as i don't need a CustomControl if i cannot combine multiple elements in it ;) (it just works in this small example as there is only one frame with one label)

So… I don't WHY but it's obvious that the calculation of the CellView-Height has a problem with nested elements that each can change it's size.
It SEEMS that at some point in a Loop the calculated Size is reseted or ignored …

I don't have a solution :(
I cannot strip out every StackLayout in my Controls and Grids that used inside a ViewCell… 

Because i like to go on, i think i have to set a fixed Row-Height, for example enough to fit two text rows, and hope for the best … Or i don't use WordWrap but trimming instead to fix it to one row :(

@bnSonic
Copy link

@bnSonic bnSonic commented Aug 10, 2019

… oh and another Problem:

UnevenRows doesn't work for the Group-Cells! If ListView has Grouping enabled, all Group-Rows are of the same height - and automatic Height-Calculation doesn't work at all… i have to set a fixed height in the CellView
(at least on iOS - not testet on Android yet)

But maybe this a completely different topic.

@ginger-777
Copy link

@ginger-777 ginger-777 commented Oct 23, 2019

… oh and another Problem:UnevenRows doesn't work for the Group-Cells! If ListView has Grouping enabled, all Group-Rows are of the same height - and automatic Height-Calculation doesn't work at all… i have to set a fixed height in the CellView(at least on iOS - not testet on Android yet)But maybe this a completely different topic.

Is there any update or workarounds?

@samhouts
Copy link
Member Author

@samhouts samhouts commented Feb 7, 2020

If you are able to, please try migrating your ListView to CollectionView to workaround this issue. Thank you!

@ttmher
Copy link

@ttmher ttmher commented Mar 10, 2020

The cheapest/easiest workaround I found, is to call Device.BeginInvokeOnMainThread(() => ListView.IsRefreshing = true) and reset it after some milliseconds in OnAppearing.

  • Depending on your list size you might need to wait some milliseconds before setting IsRefreshing to true.
  • I would also recommend to use a bool-flag to set/reset only on the first call of OnAppearing.
@chrisstaley
Copy link

@chrisstaley chrisstaley commented Apr 3, 2020

If you are able to, please try migrating your ListView to CollectionView to workaround this issue. Thank you!

Ironically, we only ran into this issue since we had to fallback to using the ListView on iOS. CollectionView had an issue wherein it was not applying the correct binding context to all of the controls in our item template. Admittedly, it is a non-trivial item template.

@samhouts
Copy link
Member Author

@samhouts samhouts commented Apr 3, 2020

@chrisstaley Oooh, that sounds interesting. Did you open an issue for the binding issue?

@chrisstaley
Copy link

@chrisstaley chrisstaley commented Apr 3, 2020

@samhouts It's been on my list of things to do. I know that a repro would be (understandably) requested, and it would take a bit of effort to pull out the code into a sample project, so that magically keeps getting pushed to the bottom of my TODO list. ;)

@samhouts
Copy link
Member Author

@samhouts samhouts commented Apr 3, 2020

@chrisstaley 😆 you know us well! I'm sorry to hear that you had to move away from CollectionView so quickly, though, so I hope we can get that resolved for you.

@lafritay
Copy link

@lafritay lafritay commented Apr 22, 2020

@samhouts

If you are able to, please try migrating your ListView to CollectionView to workaround this issue. Thank you!

I followed this advice and converted to a CollectionView. Unfortunately this bug in CollectionView causes basically the same issue:

#9520

Any chance that one of those fixes could get prioritized sometime soon?

@samhouts samhouts moved this from To do to To do-High impact in iOS Ready For Work Jun 1, 2020
@samhouts samhouts added this to the 5.0.0 milestone Aug 13, 2020
@samhouts samhouts added this to To do in vNext+1 (5.0.0) Aug 14, 2020
@nonubitta
Copy link

@nonubitta nonubitta commented Sep 30, 2020

Still waiting on this one to be fixed. Please fix this one asap. This one is really high priority and high impact.

@samhouts samhouts removed this from the 5.0.0 milestone Nov 2, 2020
@vskotatko
Copy link

@vskotatko vskotatko commented Nov 13, 2020

Not having a functioning ListView (or CollectionView) on iOS except for basic uniform height rows vastly reduces the value of Xamarin.Forms. After all, if we only want to target our apps on Android, we'll go develop directly on that platform.

@JohnHDev
Copy link

@JohnHDev JohnHDev commented Dec 28, 2020

This bug keeps getting scoped and descoped. We have tried CollectionView and it is buggy as hell (at least on iOS which is our primary market), so have reverted to ListView which 'mostly' works.
@samhouts why has this been descoped from v5?

@imuller
Copy link

@imuller imuller commented Jan 12, 2021

Same here. We have this issue in multiple of our listviews. When the viewcell content (vertical) is different on each cell, the height of the viewcell hides some of the bottom content.

@JohnHDev
Copy link

@JohnHDev JohnHDev commented Feb 4, 2021

@samhouts (or anyone that works at Microsoft actually) can you reply on why these decisions are being made? Why are customers being ignored? Why are you working on Maui when we have fundamental issues with the core product that still aren't fixed? This bug has been open for literally years. Scoped and descoped. Utter nonsense.

Does Microsoft actually want us all to migrate to Flutter? That decision is getting easier and easier every day. By the time Maui comes out (with the same bugs I expect) we'll all be using something else at this rate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
iOS Ready For Work
  
To do-High impact
Sprint 146
  
Returned to backlog
Linked pull requests

Successfully merging a pull request may close this issue.

None yet