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:
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;
Here is the screen capture of that UIViews 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.
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:
UIImageView
UILabel
= 31UILabel
UIImageView
= 31Onto 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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With