项目中需求,tableView 需要被 add到一个scrollView上。tableView的内容完全平铺出来,即设置tableView的height等于tableView.ContentSize.height。 当数据刷新的时候,table的frame也需要动态改变,这时候有可能出现ui上的问题。
原因:当你reloadData后,contentsize有可能没有及时改变。这时候你设置的话就有可能出错。
方法1: 当tableView重新布局完成后,再设置frame。你可以在下一个runloop里设置frame。
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
CGFloat calendarMinHeight = self.s_CalendarView.m_MinHeight;
CGSize remindTableViewContentSize = self.s_remindTableView.contentSize;
CGFloat bottomPadding = [UIScreen mainScreen].bounds.size.height - 64 - calendarMinHeight - remindTableViewContentSize.height;
bottomPadding = bottomPadding>=0 ? bottomPadding : 0;
// 根据tableview内容高度修改其frame高度约束
self.s_RemindTableViewHeightConstraint.equalTo(@(remindTableViewContentSize.height));
self.s_BottomPaddingViewHeightConstraint.equalTo(@(bottomPadding));
[self.s_BackdropScrollView updateConstraintsIfNeeded];
[self.s_BackdropScrollView layoutIfNeeded];
});
此延时函数,可以 理解为将代码放到下一个runloop里运行。而这时tableView 已经重新布局完成。
这种方法的缺陷是,当数据多的时候,经测试,延时时间需要设置大一点,才能布局成功。
(tableVIew计算contentSize,你需要等他布局完成)。
方法2: 自己手动计算contentSize。即你拿到新的数据,需要reloadDate时。你自己根据数据计算高度并赋值。然后reloadData。这样不用等到下一个runloop。效果较好。
NSInteger modelNum = 0;
for (int i = 0; i < modelArray.count; i++)
{
modelNum += [modelArray[i] count];
}
CGRect frame = ScheduleTable.frame;
frame.size.height = workListAry.count * HistoryCellHeight;
// 根据tableview内容高度修改其frame高度约束
self.s_RemindTableViewHeightConstraint.equalTo(@(frame.size.height));
self.s_BottomPaddingViewHeightConstraint.equalTo(@(bottomPadding));
[self.s_BackdropScrollView updateConstraintsIfNeeded];
[self.s_BackdropScrollView layoutIfNeeded];
[ScheduleTable reloadData];
题外:另外一个场景很类似。我需要在界面显示的时候,将scrollVIew指定的contentoffSet展示出来。 我在ViewDidLoad里设置scrollView.contentoffSet = (0,200),没有效果。写在ViewDidAppear里有效果。因为ViewDidLoad 和VIewWillAppear在一个runloop里,这时还没有布局完成。而ViewDidAppear已经布局完成了。但是别的问题又来了,如果你写在ViewDidAppera里,你会看到界面闪一下。 我的临时做法是
在ViewDidload里,
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
CGFloat topInset = TimeScroll.contentInset.top;
CGFloat beginOffsetY = -topInset;
CGFloat calendarViewHiddenHeight = [self.s_CalendarView intrinsicContentSize].height-self.s_CalendarView.m_MinHeight;
CGFloat endOffsetY = beginOffsetY + calendarViewHiddenHeight;
[self.s_BackdropScrollView setContentOffset:CGPointMake(0, endOffsetY) animated:NO];
});
。这相当于在下一个runloop里设置了,那是已经布局完成了。不过建议尽量不用