MARK1
// Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier:
// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath API_AVAILABLE(ios(6.0));
关于这个代理,熟悉的不能再熟了,但是没想过它是怎么工作的
测试机iPhone7 系统iOS13
数据源10 和100
发现这个方法不是你滑动的时候才加载cell,测试数据10,控制页面只能显示3个cell的时候其实这个方法给全部加载完了一遍,然后拖动的时候如果cell是从屏幕外进来的还会重新加载一遍,即它干了大量重复的工作,测试数据100的时候页面加载完成的时候,它走了14次。
结论:页面加载完毕这个方法调用次数并不等于屏幕上预计可见cell的数量,调用具体数量不知道怎么控制的(可能根据机型性能),然后屏幕滑动加载新cell时候这个方法还是会调用,只是cell已经创建好了直接去缓存池中取,意思就是这个方法针对indexPath会重复调用;willDisplayCell这个接口同步跟在cellForRowAtIndexPath后面调用次数也一致,didEndDisplayingCell这个接口并不能很好的判断cell离开屏幕的时机,首先页面加载完毕可能会加载超出屏幕可见cell的数量,willDisplayCell会和cellForRowAtIndexPath调用相同的次数,如果创建的cell非可见,didEndDisplayingCell这个方法又会被触发,其次这个方法并不能完美的契合cell离开屏幕时候就去触发的时机(感觉不到这个方法存在的意义,可能是我使用的姿势不对),建议通过scrollViewDidScroll这个接口去计算滚动距离和屏幕高度来处理
MARK2
UITableView style为grouped的时候重写frame去实现cell间距和边距效果的时候,会有不可预知的效果;另外cell需要编辑的时候也是一样(能不用grouped就不用,不可预期的bug太多);
图中有两个问题,问题一,第二组的第一个cell的顶部出现了一个分割线,其实那个cell已经设置了去掉分割线的代码
cell.separatorInset = UIEdgeInsets.init(top: 0, left: 0, bottom: 0, right: CGFloat(MAXFLOAT))
但是上面还有条线,最后是加了一行代码
tb.separatorStyle = .none
问题二,明显能感觉到 第二个section header高度有问题(其实不是header高度问题是第一个section的最后一个cell的下面多了空白,为啥说是cell没说sectionfooter呢?因为我给sectionFooter通过代理返回一个0.001并没卵用,然后第二个section的第一个cell的上面也有空白,UI看上去像是header高度变了),tableView为grouped状态,原因是:重写了第二个section下的cell的frame,但是如果tablview style 为 plain的时候是正常的,这他妈就跟玄学一样,因为苹果也没告诉你tableview是怎么去布局上面的cell的,何时会触发setFrame(会调用很多次),最后怎么”解决“的呢?我继承UIview自定义了header重写frame,把Y往上调了,高度调小了,然后代理返回的高度改小了,具体看代码吧
//自定义的header
class SectionHeader: UIView {
override var frame: CGRect{
get {
return super.frame
}
set {
var rect: CGRect = newValue
rect.origin.y -= 16
rect.size.height += 32
super.frame = rect
}
}
}
//代理返回的高度
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if section == 1 {
return CGFloat(24.0^&)
}
//代理返回的header
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if self.decDetailModel.ownerInformation.count == 0 {//请求失败没有获取到数据
return UIView()
}
if section == 0 {
return UIView()
}
let header = SectionHeader.init(frame: CGRect.init(x: 0, y: 0, width: Int(Screen_width), height: Int(56^&)))
为啥解决带了引号了,因为这玩意看起来像是解决了(UI展示达到预期了),但是不可控,你不知道为啥这样可以了,真特么的蛋疼,建议如果遇到类似这种需要组头然后cell又需要做缩进处理留边的,直接通过给cell加空白填充效果处理吧,虽然笨,但是至少是可控的
补:
tb.estimatedRowHeight = 0
tb.estimatedSectionFooterHeight = 0
tb.estimatedSectionHeaderHeight = 0
添加这三项设置后cell布局没了那种不可预知的空白或者留白,可能是这三个有默认值的关系,建议如果不影响每次都给tableview带上这三设置吧
问题三、刷新界面不带动画
DispatchQueue.main.async {
UIView.performWithoutAnimation {
self.myTableView.reloadRows(at: [index], with: .none)
}
}
注:很神奇的是必须要主线程异步执行不然界面会闪动(就算你本来是在主线程,难道执行时机会有影响?),位置还会上下偏移
问题四:调用删除api 崩溃
self.myTableView.deleteRows(at: indexs, with: .fade)
解决:必须先更新数据源,然后再delete
tableView编辑状态
网友评论