UITableView下拉刷新上下/左右顫抖問題

tableView下拉刷新顫抖bug

1. 用MJRefresh下拉刷新UIcollectionview 左右顫抖問題

  • 同學(xué)問我了一個問題,用MJRefresh下拉刷新UIcollectionview,效果如圖:
1.jpg

圖1


2.jpg

圖2


3.jpg

圖3
4.jpg

圖4
5.jpg

圖5
由于他設(shè)置的


self.UIcollectionview.contentInset = UIEdgeInsetsMake(20, 18, 30,-18);

設(shè)置了之后就出現(xiàn)這個問題。如果不設(shè)置這句話就沒有這個問題,但是跟他們UI給的效果圖就不一樣了。

  • 看了一下MJRefresh的源碼:

3.0.8以前的版本:MJRefreshHeader.m中的122行處:

  } else if (state == MJRefreshStateRefreshing) {
        [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
            // 增加滾動區(qū)域
            CGFloat top = self.scrollViewOriginalInset.top + self.mj_h;
            self.scrollView.mj_insetT = top;

            // 設(shè)置滾動位置
            self.scrollView.mj_offsetY = - top;
        } completion:^(BOOL finished) {
            [self executeRefreshingCallback];
        }];
    }

下拉刷新中給collection的offsetY重新設(shè)置了一下。

3.0.8以后的版本:MJRefreshHeader.m中的126行處:之所以改成下面這樣是為了解決刷新上下顫抖的問題把【下面的2和3模塊有解釋】

else if (state == MJRefreshStateRefreshing) {
         dispatch_async(dispatch_get_main_queue(), ^{
            [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
                CGFloat top = self.scrollViewOriginalInset.top + self.mj_h;
                // 增加滾動區(qū)域top
                self.scrollView.mj_insetT = top;
                // 設(shè)置滾動位置
                [self.scrollView setContentOffset:CGPointMake(0, -top) animated:NO];
            } completion:^(BOOL finished) {
                [self executeRefreshingCallback];
            }];
         });

給我同學(xué)的問題的解決方法:修改框架

else if (state == MJRefreshStateRefreshing) {
         dispatch_async(dispatch_get_main_queue(), ^{
            [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
                CGFloat top = self.scrollViewOriginalInset.top + self.mj_h;
                // 增加滾動區(qū)域top
                self.scrollView.mj_insetT = top;
                // 判斷了一下 這里面
                if ([self.scrollView isKindOfClass:[UICollectionView class]]) {
                    self.scrollView.mj_offsetY = - top;
                }else {
                    [self.scrollView setContentOffset:CGPointMake(0, -top) animated:NO];
                }
            } completion:^(BOOL finished) {
                [self executeRefreshingCallback];
            }];
         });

2. 解決上拉加載更多,tableview抖動問題

【問題描述】在一個自己實(shí)現(xiàn)加載更多的App中,當(dāng)上拉操作的時候,從網(wǎng)絡(luò)端下載下來數(shù)據(jù),并更新tableview,打?。喝缦?/p>

2016-04-01 19:04:16.078 [2044:865035] contentInset:{64, 0, 56, 0}
2016-04-01 19:04:16.079 [2044:865035] setContentOffset:{-0, -64}
2016-04-01 16:40:20.573 [1869:836104] contentInset:{64, 0, 172, 0}
2016-04-01 16:40:20.575 [1869:836104] setContentOffset:{0, 1441}
2016-04-01 16:40:20.789 [1869:836104] contentInset:{64, 0, 56, 0}
2016-04-01 16:40:20.792 [1869:836104] setContentOffset:{0, 1325}

從上面的log中可以看到,tableView初始化后,contentInset.bottom是56 top是64(恰好是tabBar和NaviBar的高度)。

注意:


  • 打印出現(xiàn)contentInset.bottom = 172,因?yàn)榇藭r“加載更多”的view加到了tableview的末尾,所以contentInset.bottom += “加載更多”的view.height ,最后即是172.

  • 最后,contentInset.bottom又恢復(fù)為56,這是因?yàn)椤凹虞d更多”的view隱藏了,tableview的ContentInset又恢復(fù)了。

  • 當(dāng)“加載更多”獲取數(shù)據(jù)下來,tableview更新后。由于contentInset從56—>172—>56。所以,會有一個抖動的現(xiàn)象:如下圖:

20150402193133353.gif
  • 從loading開始,加載更多后,“悄巴蜀”這個cell出來了,但是tableview先向下滑動,在向上滑動,產(chǎn)生了抖動現(xiàn)象。

【原因】

  • 當(dāng)loading的時候,contentInset.bottom是172,當(dāng)loading隱藏的時候contentInset.bottom = 56.這是因?yàn)樵趯ableview的contentInset賦值的時候,contentOffset也會相應(yīng)改變。contentOffset的變化導(dǎo)致了抖動

  • 下面的log展示了,contentInset和contentOffset相關(guān)聯(lián)的問題

2015-04-01 16:40:20.573 [1869:836104] contentInset:{64, 0, 172, 0}
2015-04-01 16:40:20.575 [1869:836104] setContentOffset:{0, 1441}
2015-04-01 16:40:20.789 [1869:836104] contentInset:{64, 0, 56, 0}
2015-04-01 16:40:20.792 [1869:836104] setContentOffset:{0, 1325}

兩次contentOffset的差值116,正好是contentInset的差值。

【解決】

  • tableview的contentInset還是要恢復(fù)的,但是contentOffset達(dá)到1441的較高值后,后面1325就可以忽略了。這樣即可解決抖動

  • 另外:當(dāng)loading失敗的時候,沒有新的cell進(jìn)來,會不會造成tableview末端懸空?

    答案是:不會懸空;這是因?yàn)椋簾o論如何contentInset一定會恢復(fù)。既然contentInset已經(jīng)恢復(fù)為56了,那么即便contentOffset在較高位置,它也會自動滑下來。因?yàn)閏ontentInset限制了tableview一定要滑回來。類似與普通的tableview,用戶手動將tableview的尾部向上拉,松手后,tableview自動還原到原來位置。

    在進(jìn)入IOS8之后,你有沒有注意到老式的下拉刷新可能會抖一下, 在下拉松開后,scrollView即將回到“刷新中…”的狀態(tài)過程中的時候。如果你有這個問題,那不妨跟隨我來看看怎么解決這個問題。

2. 解決下拉刷新,tableview抖動問題

  • 我們先來看看在手松開之后我們對scrollView做了什么事情:
ScrollViewDidEndDragging => setContentInset:

為了保證在“Loading”的狀態(tài)下,下拉刷新控件可以展示,我們對contentInset做了修改,增加了inset的top. 那這樣一步操作為什么會導(dǎo)致scrollView抖動一下呢。如下

  • 我在scrollViewDidScroll:中打了個斷點(diǎn),來看看在setContentInset:之后發(fā)生了什么事情。 我設(shè)置的inset.top = 64; 結(jié)果發(fā)現(xiàn)scrollView的contentOffset發(fā)生了這樣的變化:

    (0, -64) => (0, -133) => (0, -64)

    由以上數(shù)據(jù)可以看出,contentOffset在這個過程中先被向下移動了一段,再回歸正常。 猜測問題原因:和上面的原因是一樣的。


解決方法

網(wǎng)上的方法:async

  • 第一思路是避開這個沖突,于是我把 setContentInset: 的方法異步調(diào)用一下:
dispatch_async(dispatch_get_main_queue(), ^{
            [UIView animateWithDuration:kAnimationDuration animations:^{
                self.scrollView.contentInset = inset;
            } completion:^(BOOL finished) {
            }];
        });

不能解決
  • 修改: 強(qiáng)設(shè)contentOffset

既然是因?yàn)閏ontentOffset改變導(dǎo)致的,我就再設(shè)置一下contentOffset應(yīng)該就行了

dispatch_async(dispatch_get_main_queue(), ^{
            [UIView animateWithDuration:kAnimationDuration animations:^{
                self.scrollView.contentInset = inset;
                self.scrollView.contentOffset = CGPointMake(0, -inset.top);
            } completion:^(BOOL finished) {
            }];
        });

沒用,問題還是存在
  • 將setContentOffset: 方法改為 setConentOffset:animated: 。 問題就解決了!看來系統(tǒng)里面這兩個方法的實(shí)現(xiàn)是不同的啊。
dispatch_async(dispatch_get_main_queue(), ^{
            [UIView animateWithDuration:kAnimationDuration animations:^{
                self.scrollView.contentInset = inset;
                [self.scrollView setContentOffset:CGPointMake(0, -inset.top) animated:NO];
            } completion:^(BOOL finished) {
            }];
        });
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容