How do we use the new ListView hasunevenrows property to fit height to content on IOS?

MartinBoothMartinBooth USMember ✭✭
edited July 2014 in Xamarin.Forms

I can set the height of a viewcell to a different value for each cell in the viewcell's constructor, but what if I don't know the height at this point? Practically, this is not much use. I'm sure I'm not alone in hoping that this property can be set the height of the viewcell to the height of the content. An example of how to do this would be great.

Previously, in my own implementation of hasunevenrows (http://forums.xamarin.com/discussion/comment/63448#Comment_63448) I called:

    uiCell.SetNeedsLayout();
    uiCell.LayoutIfNeeded();

in UITableViewSource.GetHeightForRow

This caused the layout to be calculated in the ViewCell's View (in my case a StackLayout) and I could set the viewcell's height in the SizeChanged event of the StackLayout:

        this.stackLayout.SizeChanged += (sender, e) =>
            {
                var sizeRequest = this.stackLayout.GetSizeRequest(this.ParentView.Width, double.PositiveInfinity);
                this.Height = sizeRequest.Request.Height;
            };

Unfortunately, the SizeChanged event occurs too late to affect the size of the cell so I can't use this approach. What is the suggested way to set the ViewCell's height to the height of it's contents?

Best Answer

Answers

  • MartinBoothMartinBooth USMember ✭✭

    Thanks for the reply.

    Perhaps it may be useful for people describe the actual use cases for the features they are requesting. I was certainly hoping that this feature/bugfix would enable a listview's cell to expand to fit it's content.

  • ChrisgozdChrisgozd USMember ✭✭

    @CraigDunn‌ how could this be done in XAML? I am trying to do this :

     <ListView.ItemTemplate>
     <DataTemplate>
     <ViewCell Height="{Binding Height}">
    

    but Xamarin is saying : no property of name Height found, even though I have the height property as an int in my model.

  • CraigDunnCraigDunn USXamarin Team Xamurai

    Doesn't look like the ViewCell class has a HeightProperty declared for binding. Will have to raise this with the team.

    For now the workaround is to set the Height directly in OnBindingContextChanged as I do in my example.

  • MartinBoothMartinBooth USMember ✭✭
    edited July 2014

    Thanks for your suggestion @CraigDunn, unfortunately as you pointed it, this has many issues. It is only an approximation, which means it gets increasingly inaccurate the more text you have. It doesn't take into account linebreaks or paragraphs. It is not just different width letters which will affect it, but also different words will wrap in different places.

    I've created a suggestion in the hope xamarin can help enable this usecase more easily out of the box. Please vote for it if you want it to happen!

    http://xamarin.uservoice.com/forums/258559-xamarin-forms-suggestions/suggestions/6205412-make-it-possible-to-set-listview-cell-s-height-to

    @ermau could you share any of these workarounds you're looking at?

  • ryanoberleitnerryanoberleitner USUniversity ✭✭

    +1 on the workaround not being adequate for our needs. As the amount of characters you possibly have to display goes up the workaround will likely never be correct due to line breaks and such.

    We were able to get something working that seems accurate but it's using the reflection idea posted here http://forums.xamarin.com/discussion/comment/56693/#Comment_56693 to get at the UITableViewSource. Once you can access that to override the GetHeightForRow method you can get the size of your variable height UI elements and then calculate the height of your row assuming you have a bounded width on which to base the height size calculations. Very hacky and certainly not ideal but seems to be our only option.

  • CyrilCathalaCyrilCathala FRMember ✭✭

    iOS 8 introduced a painless way to auto size cells (with UITableViewAutomaticDimension and EstimatedRowHeight).
    I guess we'll have to wait for Xamarin.Forms to target iOS 8 minimum to get that ... Hopefully, with the adoption rate on iOS, we shouldn't wait too long :)

  • MustafaJalilMustafaJalil USMember ✭✭

    Hey Guys, is there any news on this issue.

    I am running into same problem and in my case its not just a label that I have got; I have like three labels placed one after the other (vertically, as a stack layout) I was wondering if there is a way to calculate height for the stackLayout on "OnBindingContextChanged" and then probably set the "Height".

    P.S The stackLayout in my case has Orientation = StackOrientation.Vertical and VerticalOptions = LayoutOptions.StartAndExpand, so essentially is whatever the label contents are it should resize the stack to accommodate them vertically. If I can somehow get the height of stack then that would be helpful, I guess..

  • FredyWengerFredyWenger CHInsider ✭✭✭✭✭

    @MustafaJalil‌:
    I have tried everything that was in my brain to find a real solution -no luck.
    I also thought, to get the real size of the elements after set the text would be a good solution (add text to label, get label size, calculate and set the "real height").
    Unfortunately all property's are on -1 at this time (OnBindingContextChange).
    So.. I had no chance to solve it until now.
    Additionally, the needed height varies from device to device (E.G. iPhone and iPad) and also from device-orientation (Portraet / Landscape).

    The longer I work with XF, the larger (and more (time) expensive) is the problem. On every ListView I use, I have to implement a (bad!) workaround.
    So.. we really need a solution from Xamarin!

    Crosslight (like XF, based on Xamarin), shows, that a solution is possible with Xamarin:
    intersoftpt.com/News/August2014.html

    Specially see "iOS Automatic Row Height Calculation" and "Buttery-Smooth Scrolling in iOS".

    See also newest version:
    developer.intersoftpt.com/display/crosslight/Crosslight+3.0+Release+Notes

    Note: I don't have used Crosslight until now and don't know, If all the promises are hold...
    But it sounds rally good (I wish XF would be Crosslight right now!).

  • AdamPAdamP AUUniversity ✭✭✭✭✭
    edited December 2014

    Just sharing a way found to more accurately calculate the height requirements for text.

    I just use UIScreen.MainScreen.Bounds.Width - "my padding" to determine the width.

    private Double EstimateHeight(String text, Int32 width, UIFont font)
        {
    
            SizeF size = ((NSString)text).StringSize(font, new SizeF(width, float.MaxValue), UILineBreakMode.WordWrap);
            return (Double)size.Height + 50; // The 50 is just padding
    
        }
    
  • FredyWengerFredyWenger CHInsider ✭✭✭✭✭

    @AdamPedley‌ :
    Thanks for your posting.
    Looks very interesting - I try it out next year (as I am in holiday now :blush: )

  • @CraigDunn i try your example for iOS (https://github.com/conceptdev/xamarin-forms-samples/blob/master/Evolve13/Evolve13/Views/SessionCell.cs#L45-L60 without success!

    My workaround is to set the ListView.RowHeight and truncate Text inside row to avoid overflow.

    In this way I cannot have full control of single row. Infact i have row with 20 char and other row with 200 char! With this solution i need to truncate at 100 char to have a graphic acceptable but not perfect! :neutral:

    Can you help me?

    Esteban

  • FredyWengerFredyWenger CHInsider ✭✭✭✭✭

    @AdamP:
    It seems, as your code is iOS-spezific-code (SizeF, NSSTring and UILineBreakMode are not know in XF)...?
    Can you please post the full solution, how you have implement it in Xamarin.Forms?
    Thanks

  • CraigDunnCraigDunn USXamarin Team Xamurai
  • FredyWengerFredyWenger CHInsider ✭✭✭✭✭

    @Adamp:
    Thanks for your posting - you have your first like :smile:
    Further questions:
    Can you post also a small example, how you use it in XF?
    What about performance to default renderer (equal / faster / slower)?
    Thanks for a further reply.

  • AdamPAdamP AUUniversity ✭✭✭✭✭

    @FredyWenger - you don't need to do anything further in Xamarin forms. By adding

    [assembly: ExportRenderer(typeof(ViewCell), typeof(MyListViewCellRenderer))]
    

    To the top of the renderer as shown in the example above it overrides the rendering of all ViewCells on all pages. The example I have above, just take that code and place it in a class file in the iOS project. It just acts as a custom renderer for iOS and doesn't affect any other project.

    In terms of performance I haven't noted any improvements or slow downs, though I have not done any specific testing of performance on this front.

  • FredyWengerFredyWenger CHInsider ✭✭✭✭✭

    @AdamP:
    Thanks for your further replay - I understand.
    Last questions:
    What about the custom class ResponseView?
    In your custom renderer, you have fix-coded the font ("Helvetic Neue" and the font-size (18).
    => I think, this can cause problems if other Fonts, FontSizes are used...?

  • AdamPAdamP AUUniversity ✭✭✭✭✭

    @FredyWenger Yes, other fonts could cause an issue but you could pass them through to what you require.

    The custom class ResponseView is just a straight up plain old class that I have in a list that I bind to the listview. You can bind whatever datasource you want to the listview, then just use that object type instead of ResponseView.

    However you need have something defined here as its the only way to pass the contents of the cell to this function so that it can determine the height.

  • vinodkumarvinodkumar INMember ✭✭
    edited May 2016

    For me, below code worked.

    protected override void OnAppearing()
    {
    base.OnAppearing();
    listViewOrderCloths.HeightRequest = (model.ListOrderedCloths.Count*100)/2 ;
    }

  • ShimmyWeitzhandlerShimmyWeitzhandler USMember ✭✭✭
    edited July 2017

    Any updates?
    I'm desperately looking for a way to determine View/Cell's estimated logical height. The RenderedHeight always returns 40.

    I'm struggling with making XF ListView shrink and expand according to its contents. As someone who comes from the WPF world, I'm pulling my hair out trying to figure out why this trivial task has to be so hard to achieve.

    See this issue.

Sign In or Register to comment.