Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tableheader view autolayout issue

I'm loading a custom UIView's XIB file as a header view of a uitableview inside a view controller.

The file owner for the xib file is the viewcontroller. I have both the viewcontroller's & the uiview's interface declared inside the uiviewcontroller.

ViewController.h

      @class ZeroStateView;

      @interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>

      @property (nonatomic, weak) IBOutlet CustomUITableView *tableView;
      @property (nonatomic,strong) NSMutableArray *dataArray;
      @property (weak, nonatomic) IBOutlet ZeroStateView *zeroStateView;


      @end


     @interface ZeroStateView : UIView
     @property (weak, nonatomic) IBOutlet AutoLayoutLabel *titleLabel;
     @property (weak, nonatomic) IBOutlet UIImageView *titleIcon;

     - (void)updateView;

     @end

ViewController.m

    - (void)prepareHeaderViewForZeroState{
            ZeroStateView *sizingView = [ZeroStateView new];
            [[[NSBundle mainBundle] loadNibNamed:@"ZeroStateView" owner:self options:nil] objectAtIndex:0];
            sizingView = self.zeroStateView;
           [sizingView updateView];

           self.tableView.tableHeaderView = sizingView;

           UIView *headerView = self.tableView.tableHeaderView;



           CGFloat height = [headerView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

         CGRect headerFrame = headerView.frame;
         headerFrame.size.height = height;
         headerView.frame = headerFrame;


         self.tableView.tableHeaderView = headerView;
     }

    @end

    @implementation ZeroStateView

    -(void)updateView{
      self.titleIcon.alpha = 0.5;

      UIFontDescriptor *titleFontDescriptor = [UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleSubheadline];

      self.titleLabel.text =  @"This is a long text message and its really long. This is a long text message and its really long. This is a long text message and its really long. This is a long text message and its really long. This is a long text message and its really long. This is a long text message and its really long. This is a long text message and its really long. This is a long text message and its really long. ";

     }

The AutolayoutLabel class the following method overridden:

   - (void)setBounds:(CGRect)bounds {
      [super setBounds:bounds];

      // For multiline label, preferredMaxLayoutWidth always matches the frame width
      if (self.numberOfLines == 0 && bounds.size.width != self.preferredMaxLayoutWidth) {
          self.preferredMaxLayoutWidth = self.bounds.size.width;
          [self setNeedsUpdateConstraints];
      }
   }

The height calculated by the systemLayoutSizeFittingSize:UILayoutFittingCompressedSize returns 0. As a result I get the following view as the table header view: Header view with height 0

When I added the actual height as below, the uilabel overflows. I'm expecting the uiview to grow as the label height grows.

 headerFrame.size.height = self.sizingView.frame.size.height;

TableHeaderView not being resized properly

Here is the screen capture of that UIViews constraints:

ZeroState view XIB file with constraints

What do I miss here? Can someone point me out?

Update I created a sample project for you guys to check on whats exactly issue is.

like image 330
Siddharthan Asokan Avatar asked Sep 28 '22 02:09

Siddharthan Asokan


2 Answers

I reimplemented what you had so far in a different way. To start, I removed the UIView in ZeroStateView.xib that the UIImageView and UILabel were embedded in. The base of the xib is already a UIView, so it is unnecessary to add another UIView to it.

Next I changed the constraints around. I don't remember exactly what constraints I changed, so I will just list them out here:

  1. Constraints for UIImageView
    • Align Center X to Superview
    • Width = 60
    • Height = 56
    • Top Space to Superview = 37
    • Bottom Space to UILabel = 31
  2. Constraints for UILabel
    • Left Space to Superview = 15
    • Right Space to Superview = 15
    • Bottom Space to Superview = 45
    • Top Space to UIImageView = 31

Onto the code. In ViewController.h, the IBOutlet wasn't doing anything as far as I could tell, so I changed that property to read @property (strong, nonatomic) ZeroStateView *zeroStateView;

Now the important changes: ViewController.m. There are two UITableViewDelegate methods that will replace prepareHeaderViewForZeroState. In viewDidLoad, initialize the zeroStateView and set the table view's delegate to self.

- (void)viewDidLoad
{
    //...

    // Load the view
    self.zeroStateView = [[[NSBundle mainBundle] loadNibNamed:@"ZeroStateView" owner:self options:nil] firstObject];
    [self.zeroStateView updateView];
    self.zeroStateView.backgroundColor = [UIColor darkGrayColor];

    // Set self for table view delegate for -heightForHeaderInSection: and viewForHeaderInSection:
    self.dataTable.delegate = self;
}

Now that we are the table view's delegate, we get two method calls that will allow us to customize the header view and set its height appropriately.

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    // This will set the header view to the zero state view we made in viewDidLoad
    return self.zeroStateView;
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    // sizeToFit describes the size that the label can fit itself into.
    // So we are saying that the label can use the width of the view and infinite height.
    CGSize sizeToFit = CGSizeMake(self.view.frame.size.width, MAXFLOAT);

    // Then we ask the label to tell us how it can fit in that size.
    // The label will respond with the width of the view and however much height it needs
    // to display its text. This is the magic of how it grows vertically.
    CGSize size = [self.zeroStateView.titleLabel sizeThatFits:sizeToFit];

    // Add the height the label needs to the overall zero state view. This should be changed
    // to the height of the UIImage + the height we just got + the whitespace above and below
    // each of these views. You can handle that part.
    return self.zeroStateView.frame.size.height + size.height;
}

I uploaded my changes to Dropbox here.

like image 120
keithbhunter Avatar answered Oct 03 '22 07:10

keithbhunter


Just changing the size of the frame of the tableHeaderView, doesn't change it's size. You have to set it again to the tableView to force a reload.

You have to call this again self.tableView.tableHeaderView = headerView; after setting the new frame size.

like image 40
pteofil Avatar answered Oct 03 '22 06:10

pteofil