首语
今天项目中一个需求,具体原型图如下图。
原始需求图
需要在设置了 UITableView
为 UITableViewStyleGrouped
样式后,头部需要设置一个温馨提示的标签。本来实现的方式有多种方式,比如:
- ① 可以选择通过
tableHeaderView
属性创建一个UIView
,并在其上添加一个UILabel
即可以实现。
@property (nonatomic, strong, nullable) UIView *tableHeaderView;
// accessory view for above row content. default is nil. not to be confused with section header
- ② 可以选择通过下面方法直接返回
title
即可以实现。
- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
// fixed font style. use custom view (UILabel) if you want something different
- ③ 可以通过下面方法直接自定义
viewForHeaderInSection
,并在其上添加一个UILabel
即可以实现。
- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
// custom view for header. will be adjusted to default or specified header height
本以为最多几分钟的事儿,基本上就可以实现了。但是天公如此不作美,发现效果比较骨感,上一下效果图(这里是测试 Demo,只是简例)。
第一次实现效果图备注:
环境:Xcode 9.4.1,iOS 11.4
初次实现效果问题
看看效果,嗯?第一个 sectionHeader
的高度和其他的一样?
有问题!
有问题!
绝对有问题!
此处上一下写得代码(测试 Demo):
//
// ViewController.m
// TestDemo11
//
// Created by 苜蓿鬼仙 on 2018/7/23.
// Copyright © 2018 苜蓿鬼仙. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()<UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, strong) UITableView *tableView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 64, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height-64) style:UITableViewStyleGrouped];
self.tableView.backgroundColor = [UIColor lightGrayColor];
self.tableView.dataSource = self;
self.tableView.delegate = self;
self.tableView.rowHeight = 50;
self.tableView.showsVerticalScrollIndicator = NO;
[self.view addSubview:self.tableView];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 5;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if (section == 0) {
return @"温馨提示:左滑列表可以编辑广告";
}
return nil;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if (section == 0) {
return 40;
} else {
return 20;
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return CGFLOAT_MIN;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
cell.textLabel.text = [indexPath description];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
@end
想想以前也是如此写得呀,貌似没有啥子问题呀,经过调试发现:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if (section == 0) {
return 40;
} else {
return 20;
}
}
这个方法只调用了一次。
这就肯定不对了,如果只会调用一次的话,则肯定所有的高度都会和第一个 sectionHeader
的高度相同了。后面又再次调试了一段时间,发现没有灵感,然后向群里的一些大神们求助,发现相同的代码及环境,发现大神们的并没有任何问题,唯一的区别就是大神们是通过 StoryBoard
创建的,我这边则是通过纯代码
创建的。
然后我也尝试通过 StoryBoard
创建了一下,发现问题解决了!!!
这是闹哪样???逗我呢???肯定有猫腻!!!
最后经过大神的提醒,发现了一些猫腻,是关于 自动计算(UITableViewAutomaticDimension)
上的问题。
系统UITableView 的 API
@property (nonatomic) CGFloat rowHeight; // default is UITableViewAutomaticDimension
@property (nonatomic) CGFloat sectionHeaderHeight; // default is UITableViewAutomaticDimension
@property (nonatomic) CGFloat sectionFooterHeight; // default is UITableViewAutomaticDimension
@property (nonatomic) CGFloat estimatedRowHeight NS_AVAILABLE_IOS(7_0); // default is UITableViewAutomaticDimension, set to 0 to disable
@property (nonatomic) CGFloat estimatedSectionHeaderHeight NS_AVAILABLE_IOS(7_0); // default is UITableViewAutomaticDimension, set to 0 to disable
@property (nonatomic) CGFloat estimatedSectionFooterHeight NS_AVAILABLE_IOS(7_0); // default is UITableViewAutomaticDimension, set to 0 to disable
// Variable height support
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;
// Use the estimatedHeight methods to quickly calcuate guessed values which will allow for fast load times of the table.
// If these methods are implemented, the above -tableView:heightForXXX calls will be deferred until views are ready to be displayed, so more expensive logic can be placed there.
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(7_0);
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForHeaderInSection:(NSInteger)section NS_AVAILABLE_IOS(7_0);
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForFooterInSection:(NSInteger)section NS_AVAILABLE_IOS(7_0);
// Section header & footer information. Views are preferred over title should you decide to provide both
- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section; // custom view for header. will be adjusted to default or specified header height
- (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section; // custom view for footer. will be adjusted to default or specified footer height
从此处可以看到这个系统的 API,默认都是 UITableViewAutomaticDimension 自动计算的模式。
然后我们再看看 StoryBoard
中这些参数是如何的:
从此处可以看出 StoryBoard 中,除了
Row Height
是默认Automatic
自动计算的,Header Height
和Footer Height
都不是默认Automatic
动计算的。
但是依据上面的系统 API 可以看出,如果是纯代码写得,应该是默认全部都是
Automatic
自动计算的。
看来问题应该就是出在这里了,赶紧改代码试试。
解决方案
@property (nonatomic) CGFloat estimatedSectionHeaderHeight NS_AVAILABLE_IOS(7_0); // default is UITableViewAutomaticDimension, set to 0 to disable
@property (nonatomic) CGFloat estimatedSectionFooterHeight NS_AVAILABLE_IOS(7_0); // default is UITableViewAutomaticDimension, set to 0 to disable
self.tableView.estimatedSectionHeaderHeight = 0;
self.tableView.estimatedSectionFooterHeight = 0;
estimatedSectionHeaderHeight
和estimatedSectionFooterHeight
都设置为0
,即可以取消Automatic
自动计算了。
最终代码及效果图
//
// ViewController.m
// TestDemo11
//
// Created by 苜蓿鬼仙 on 2018/7/23.
// Copyright © 2018 苜蓿鬼仙. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()<UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, strong) UITableView *tableView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 64, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height-64) style:UITableViewStyleGrouped];
self.tableView.backgroundColor = [UIColor lightGrayColor];
self.tableView.dataSource = self;
self.tableView.delegate = self;
self.tableView.rowHeight = 50;
self.tableView.estimatedSectionHeaderHeight = 0;
self.tableView.estimatedSectionFooterHeight = 0;
self.tableView.showsVerticalScrollIndicator = NO;
[self.view addSubview:self.tableView];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 5;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if (section == 0) {
return @"温馨提示:左滑列表可以编辑广告";
}
return nil;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if (section == 0) {
return 40;
} else {
return 20;
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return CGFLOAT_MIN;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
cell.textLabel.text = [indexPath description];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
@end
最终效果图
网友评论