1. 程式人生 > >設定tableViewContentSize為自身高度時,佈局出錯的解決辦法

設定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

, (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_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裡設定了,那是已經佈局完成了。不過建議儘量不用