0

Normally iOS 8 should be able to calculate the height of a cell itself. This is working so far, but if I rotate the device the cell gets back to its standard height of 44 points.

This is how it should look like: This is working

This is how it does look like after rotation: After rotation

Once rotated it stays in that layout. It never calculates the real height anymore. I don't know why. I have added my complete code. For the constraints have a look into updateConstraints. The code is in C# but you should be able to read it. You can post your solution of course in Objective-C.

VC viewDidLoad:

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();

    this.TableView.Source = new TestSource (this);
    this.TableView.RegisterClassForCellReuse (typeof(CustomCell), TestSource.cellIdentifier);
    //this.TableView.RowHeight = 83;
}

My data source:

public class TestSource : UITableViewSource
{
    public static readonly NSString cellIdentifier = new NSString("CustomCell");
    private TestTableVC controller;

    public TestSource (TestTableVC controller)
    {
        this.controller = controller;
    }

    public override int RowsInSection (UITableView tableview, int section)
    {
        return 10;
    }

    public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
    {
        CustomCell cell = tableView.DequeueReusableCell (cellIdentifier) as CustomCell;

        cell.UpdateCell ("Max Mustermann", "m", new DateTime (2014, 12, 10), "1234567890");

        cell.SetNeedsUpdateConstraints ();
        cell.UpdateConstraintsIfNeeded ();

        return cell;
    }
}

My CustomCell:

public class CustomCell : UITableViewCell
{
    public static readonly NSString cellIdentifier = new NSString("CustomCell");

    private UILabel fullNameLabel, genderLabel, birthdateLabel, iNumberLabel;
    private bool didSetupConstraints = false;

    public CustomCell ()
    {
        this.CreateView ();
    }

    public CustomCell (IntPtr handle) : base(handle)
    {

        this.CreateView ();
    }

    public void UpdateCell (string fullName, string gender, DateTime? birthdate, string iNumber)
    {
        fullNameLabel.Text = fullName;
        genderLabel.Text = "Gender" + ": " + gender;
        birthdateLabel.Text = "Born on" + ": " + dateOfBirth.ToString ("dd.MM.yyyy");
        iNumberLabel.Text = iNumber;
    }

    public override void LayoutSubviews()
    {
        base.LayoutSubviews();

        this.ContentView.SetNeedsLayout();
        this.ContentView.LayoutIfNeeded();
    }

    public override void UpdateConstraints()
    {
        if (!didSetupConstraints) {
            NSMutableDictionary viewsDictionary = new NSMutableDictionary ();
            viewsDictionary ["fullNameLabel"] = fullNameLabel;
            viewsDictionary ["genderLabel"] = genderLabel;
            viewsDictionary ["birthdateLabel"] = birthdateLabel;
            viewsDictionary ["iNumberLabel"] = iNumberLabel;

            fullNameLabel.TranslatesAutoresizingMaskIntoConstraints = false;
            genderLabel.TranslatesAutoresizingMaskIntoConstraints = false;
            birthdateLabel.TranslatesAutoresizingMaskIntoConstraints = false;
            iNumberLabel.TranslatesAutoresizingMaskIntoConstraints = false;


            // Sizing of content view is differently in iOS 7 (autoresizing mask) and iOS 8 (layoutSubViews).
            // Don't know why this occurs but it should only concern nibs and if you are using iOS 8 SDK and compile for iOS 7.
            // http://stackoverflow.com/questions/24750158/autoresizing-issue-of-uicollectionviewcell-contentviews-frame-in-storyboard-pro
            // http://stackoverflow.com/questions/19132908/auto-layout-constraints-issue-on-ios7-in-uitableviewcell
            // bug?
            if (!UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
                // only one of these statements is needed
                this.ContentView.AutoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth;
                this.ContentView.Bounds = new RectangleF (0, 0, 99999, 99999);
            }

            this.ContentView.AddConstraints (NSLayoutConstraint.FromVisualFormat ("H:|-[fullNameLabel]", (NSLayoutFormatOptions)0, null, viewsDictionary));
            this.ContentView.AddConstraints (NSLayoutConstraint.FromVisualFormat ("H:|-[genderLabel]|", (NSLayoutFormatOptions)0, null, viewsDictionary));
            this.ContentView.AddConstraints (NSLayoutConstraint.FromVisualFormat ("H:|-[birthdateLabel]", (NSLayoutFormatOptions)0, null, viewsDictionary));
            this.ContentView.AddConstraints (NSLayoutConstraint.FromVisualFormat ("V:|-(8)-[fullNameLabel]-(5)-[genderLabel]-(5)-[birthdateLabel]-(8)-|", (NSLayoutFormatOptions)0, null, viewsDictionary));
            this.ContentView.AddConstraint (NSLayoutConstraint.Create (iNumberLabel, NSLayoutAttribute.CenterY, NSLayoutRelation.Equal, this.ContentView, NSLayoutAttribute.CenterY, 1, 0));
            this.ContentView.AddConstraints (NSLayoutConstraint.FromVisualFormat ("H:[iNumberLabel]-|", (NSLayoutFormatOptions)0, null, viewsDictionary));

            didSetupConstraints = true;
        }

        base.UpdateConstraints ();
    }

    private void CreateView()
    {
        fullNameLabel = new UILabel () {
            Font = UIFont.BoldSystemFontOfSize(17),
            TextColor = UIColor.Black,
            BackgroundColor = UIColor.Clear,
            LineBreakMode = UILineBreakMode.TailTruncation,
            Lines = 0,
            TextAlignment = UITextAlignment.Left
        };
        genderLabel = new UILabel () {
            Font = UIFont.SystemFontOfSize(15),
            TextColor = UIColor.Black,
            BackgroundColor = UIColor.Clear,
            LineBreakMode = UILineBreakMode.TailTruncation,
            Lines = 0,
            TextAlignment = UITextAlignment.Left
        };
        birthdateLabel = new UILabel () {
            Font = UIFont.SystemFontOfSize(15),
            TextColor = UIColor.Black,
            BackgroundColor = UIColor.Clear,
            LineBreakMode = UILineBreakMode.TailTruncation,
            Lines = 0,
            TextAlignment = UITextAlignment.Left
        };
        iNumberLabel = new UILabel () {
            Font = UIFont.SystemFontOfSize(15),
            TextColor = UIColor.Black,
            BackgroundColor = UIColor.Clear,
            LineBreakMode = UILineBreakMode.TailTruncation,
            Lines = 0,
            TextAlignment = UITextAlignment.Right
        };

        ContentView.AddSubviews (fullNameLabel, genderLabel, birthdateLabel, iNumberLabel);

    }

}

Is something wrong with my constraints or is this another iOS 8 bug? BTW: I'm using Xcode 6.1 with the iOS 8.1 SDK and want to support iOS 7 as iOS 8 devices. iOS 7 is another story.

testing
  • 19,681
  • 50
  • 236
  • 417
  • 1
    In viewWillTransitionToSize function, set `self.tableView.estimatedRowHeight = your estimated row height`. – gabbler Nov 12 '14 at 07:52
  • @gabbler: Seems to do the trick. But why do I need that? Would implementing `estimatedHeightForRowAtIndexPath` do the same? – testing Nov 12 '14 at 08:06
  • OK, I tried it out and it does not do the same. Also setting the estimated row height in `willRotateToInterfaceOrientation:duration` doesn't work. Strange ... – testing Nov 12 '14 at 08:12
  • what if you add `TableView.RowHeight = UITableViewAutomaticDimension` in viewdidload and remove the `SetNeedsUpdateConstraints` and `UpdateConstraintsIfNeeded` functions. – gabbler Nov 12 '14 at 08:19
  • Without `SetNeedsUpdateConstraints` and `UpdateConstraintsIfNeeded` the table view is complete empty and also has it's default size (of the cells). `this.TableView.RowHeight = UITableView.AutomaticDimension;` alone doesn't help. In these test cases I didn't used `EstimatedRowHeight` at all. Should I? – testing Nov 12 '14 at 08:23
  • You can try to add it and test again. – gabbler Nov 12 '14 at 08:28
  • No, still the same behavior (empty table). I took the basic behavior from [this SO answer](http://stackoverflow.com/questions/18746929/using-auto-layout-in-uitableview-for-dynamic-cell-layouts-variable-row-heights/18746930#18746930), where these both methods are used. So I think it's needed here and it seems setting the `estimatedRowHeight` in `viewWillTransitionToSize` is the only option. Do you know why I need this? – testing Nov 12 '14 at 08:31
  • Did it work for you? Possibly because tableview does reloading its visible cell when rotation happens. And it loses track of the height, it seems it doesn't know what height to expect. – gabbler Nov 12 '14 at 08:38
  • Yes, the first approach does work for me. It's the strange behavior I experienced the last times. Normally, I wouldn't expect that it loses the height. There were multiple things which behaves in a strange manner (iOS 7 vs. iOS 8, `UIView-Encapsulated-Layout-Height`, ...). Thanks for your help. Perhaps you post a full answer which I can mark as accepted. – testing Nov 12 '14 at 08:43

1 Answers1

4

In viewWillTransitionToSize function, set self.tableView.estimatedRowHeight = your estimated row height, it seems to be able to fix the problem, and perhaps it is a bug from apple which can be improved in the future.

gabbler
  • 13,626
  • 4
  • 32
  • 44