設定tableViewContentSize為自身高度時,佈局出錯的解決辦法
專案中需求,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
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_BackdropScrollViewupdateConstraintsIfNeeded];
[self.s_BackdropScrollViewlayoutIfNeeded];
});
此延時函式,可以 理解為將程式碼放到下一個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_BackdropScrollViewupdateConstraintsIfNeeded];
[self.s_BackdropScrollViewlayoutIfNeeded];
[ScheduleTablereloadData];
題外:另外一個場景很類似。我需要在介面顯示的時候,將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_CalendarViewintrinsicContentSize].height-self.s_CalendarView.m_MinHeight;
CGFloat endOffsetY = beginOffsetY + calendarViewHiddenHeight;
[self.s_BackdropScrollViewsetContentOffset:CGPointMake(0, endOffsetY) animated:NO];
});
。這相當於在下一個runloop裡設定了,那是已經佈局完成了。不過建議儘量不用