Reputation: 379
I'm writing a expandable tableView header, I need to set the height of header accurately in tableView delegate method. I'm now using the following method to calculate the height of my header(a multi-line label):
CGRect calcuRect = [headerText boundingRectWithSize:CGSizeMake(myLabelWitdh, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:myLabelFont} context:nil];
CGFloat headerHeight = calcuRect.size.height;
However, I've found that the height calculated out is just about the text without include line space. So how can I get the line space height of the label? or how to get accurate height of UILabel with line space?
Upvotes: 6
Views: 8940
Reputation: 950
Based on Rajan Maheshwari answer I wrote this function in Swift 3.0 for a generic label with the optional line height. Hope it helps.
func heightForLabel(_ text: String, font: UIFont, width: CGFloat, lineSpacing: CGFloat) -> CGFloat {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = font
if lineSpacing > 0.0 {
let style = NSMutableParagraphStyle()
style.lineSpacing = lineSpacing
style.alignment = .center
label.attributedText = NSAttributedString(string: text, attributes: [NSParagraphStyleAttributeName: style])
} else {
label.text = text
}
label.sizeToFit()
return label.frame.height
}
Upvotes: 1
Reputation: 14571
You can get the exact height of UILabel with exactly passing the same font size and type and doing some calculations.
Here I used a UILabel with Helvetica font with font size 16.
Objective C
- (CGFloat)requiredHeight:(NSString*)labelText{
UIFont *font = [UIFont fontWithName:@"Helvetica" size:16.0];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, CGFLOAT_MAX)];
label.numberOfLines = 0;
label.lineBreakMode = NSLineBreakByWordWrapping;
label.font = font;
label.text = labelText;
[label sizeToFit];
return label.frame.size.height;
}
Output
CGFloat size = [self requiredHeight:@"iOS Rocks"];
NSLog(@"%f",size);
size = [self requiredHeight:@"iOS Rocks\n"];
NSLog(@"%f",size);
Console Output
2016-04-10 01:37:46.812 testPro[6093:327503] 18.500000
2016-04-10 01:37:46.814 testPro[6093:327503] 37.000000
Swift 2.2
func requiredHeight(labelText:String) -> CGFloat {
let font = UIFont(name: "Helvetica", size: 16.0)
let label:UILabel = UILabel(frame: CGRectMake(0, 0, 200, CGFloat.max))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.ByWordWrapping
label.font = font
label.text = labelText
label.sizeToFit()
return label.frame.height
}
Edit
Swift 3.0
func requiredHeight(labelText:String) -> CGFloat {
let font = UIFont(name: "Helvetica", size: 16.0)
let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: .max))
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.font = font
label.text = labelText
label.sizeToFit()
return label.frame.height
}
Upvotes: 9
Reputation: 379
In fact, I want to create an expandable section header in my table view, however in the delegate method:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
this method must return the exactly height of my label header, I use the following method to calculate the height, however the height do not include line space but only words height;
- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(NSDictionary<NSString *, id> *)attributes context:(NSStringDrawingContext *)context;
Since know more about sizeToFit, here is a feasible answer
- (void)viewDidLoad {
[super viewDidLoad];
[self tableViewInit];
[self headerInit];
}
- (void)tableViewInit {
self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:_tableView];
self.tableView.dataSource = self;
self.tableView.delegate = self;
}
- (void)headerInit {
CGRect originSize = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, CGFLOAT_MIN);
self.header = [[UILabel alloc] initWithFrame:originSize];
self.header.lineBreakMode = NSLineBreakByWordWrapping | NSLineBreakByTruncatingTail;
self.header.text = self.headerStr;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if (self.showAll) {
self.header.numberOfLines = 0;
[self.header sizeToFit];
} else {
self.header.numberOfLines = 2;
[self.header sizeToFit];
}
return self.header.bounds.size.height;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
return self.header;
}
Upvotes: 0
Reputation: 370
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
sizeToFit()
}
func sizeToFit(){
let header = customHeaderView
let height = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height;
var headerFrame = header.frame
headerFrame.size.height = height
header.frame = headerFrame
tableView.tableHeaderView = header;
}
Hope this will help you.
Upvotes: 0
Reputation: 2132
Use below methods for same.
- (CGFloat)heightForWidth:(CGFloat)width usingFont:(UIFont *)font withText:(NSString *)aStrText
{
CGSize labelSize = (CGSize){width, FLT_MAX};
CGRect rect = [aStrText boundingRectWithSize:labelSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName : font}
context:nil];
return rect.size.height;
}
Upvotes: 0