高仿Boss直聘招聘詳情頁面上拉返回效果

先上效果圖:


bossDemo錄屏.gif

代碼地址:https://github.com/huisaziru/BossHireDemo

最近正在找工作,然后用Boss直聘這個軟件試了下,發現招聘詳情頁面上拉挺有意思的,很容易被迷惑;上拉時,拉到底再往上拉時能看到首頁的view,而且滾動條好像是在下面那個view上;

一開始以為上面那個只是一個tableview添加在首頁的那個view上,后面發現下面那個tabbarcontroller縮小了,并且返回的時候,和dissmiss一樣,基本確定是首頁present出來這個詳情頁;

分析上拉返回實現

詳情頁有一個tableview,tableview需要加在scrollview上,scrollview是橫向滾動,用來獲取其他招聘詳情;
要實現這個效果,以下條件可以滿足:

  • scrollview在拖動的時候是透明,不拖動時為不透明,因為需要橫向滾動
  • tableview什么時候都透明,拉到底再往上拉的時候,如果不透明,就會出現tableview的背景色,就擋住了下面;
  • menuview是和tableview同一級,一開始是不透明的,需要一個containerview包含它們,然后containerview加在scrollview上;因為tableview動的時候menuview不動,拉到底再往上拉時候才跟著動;所以menuview不在tableview上;

看上去這些就能實現這個功能,但是有個細節很重要,就是滾動條滾到menuview下面的時候,只有滾動條透過menuview

當時看到這個效果的時候有點懵,為什么只有滾動條可以透過menuview;按理講要透明的話,應該全部都會透過去,看得到下面;這個是最難的地方;

后面想到了局部透明,隨著往上拉,menuview慢慢的從上往下透明,剛好讓進來的滾動條透出來,但是有個問題:透明出來的部分還是會把下面的東西透出來,不單單只透明滾動條;

這時我想到找一個背景view放在menuview局部透明位置的底下,讓上面的透明區域被下面擋?。贿@里注意不能是menuview大小,要不然擋住了下面,但是這時會將滾動條擋住,真是糾結;

現在的問題是:底下的那個背景view怎么不擋住滾動條?

分析:滾動條是在tableview 上面的,所以可以從tableview入手,將背景view加到tableview底部:contentsize底部下面--因為只有拉到底這個背景view才能出來;

驗證一下:當拉倒底,再往上拉時,menuview慢慢透出上面,這時候背景view慢慢出來,剛好擋住透明部分,這時滾動條被menuview可以透過;到這里基本宣告成功!

menuview透出來

還有一個點沒說:就是menuview怎么慢慢透出來,我想的辦法是,menuview底下有一個白色不透明的maskview,上面就是放按鈕的containerView,這個view的背景顏色帶透明;

  • 初始狀態:上面透明部分被下面maskview擋住
  • 拉到底往上拉時:maskview的y慢慢變大,高變成maskview.height - y,這樣就能將上面的containerView慢慢透出來
  • 當maskview的y等于maskview.height時,等于全透了,這時tableview的背景view剛好全出來了,完全擋住menu view;

我發現Boss直聘有一個bug,正是這個bug論證了我的猜想;當拉到底時,再往上拉一段距離,這時快速拉下來,神奇的現象就發生了:menuview已經不在底下了,最重要的是,它上部分是透明的,可以透過看到tableview的字;這個bug很好解決,就是突然下來導致的,沒有過渡,只需在當前offset沒有到底的時,將menuview的坐標復原就可以;

到這里終于是搞定了!!!


以下是上面主要的實現代碼

背景view:這里要注意的是,因為boss直聘的詳情頁支持scrollview切換,這里只用一個tableview,當數據變化時,contentsize就會變,這時候需要更新背景view的frame,這里用kvo檢測tableview的content size就可以實現這個;

    //tableFooterBackGroundView作用:當tableview拉到底,再往上拉時,menuview 慢慢透出來的部分,如果底下沒有view,會看到下面,所以添加此view,位置在tableview底部下面
    self.tableFooterBackGroundView = [[UIView alloc] initWithFrame:CGRectMake(0, self.tableView.contentSize.height, frame.size.width, MenuHeight)];
    self.tableFooterBackGroundView.backgroundColor = [UIColor whiteColor];
    [self.tableView addSubview:self.tableFooterBackGroundView];
    
    // 對tableView的contentSize 進行kvo,因為每次請求的數據不一樣,conentSize不一樣,更新tableFootBackGroundView的top
    [self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];

menuview:

/** 菜單view,和tableview同一級*/
- (UIView *)createMenuView:(CGRect)frame {
    UIView *containerView = [[UIView alloc] initWithFrame:frame];
    
    //遮罩view的作用:tableview上升時,遮罩view慢慢變小,讓menuview透出來 tableFooterBackGroundView慢慢出來,剛好擋住了透明的部分,滾動條在tableview之上,所以可以透過menuview
    self.contentMenuMaskView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
    self.contentMenuMaskView.backgroundColor = [UIColor whiteColor];
    [containerView addSubview:self.contentMenuMaskView];
    
    UIView *menuView = [[[NSBundle mainBundle] loadNibNamed:@"MenuView" owner:self options:nil] firstObject];
    menuView.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);
    menuView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8];
    [containerView addSubview:menuView];
    
    return containerView;
}

滾動處理:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView.contentSize.height > 0 && scrollView.tag == 0) {//拉到底
        if (scrollView.contentOffset.y + scrollView.height > scrollView.contentSize.height) {
            self.scrollView.backgroundColor = [UIColor clearColor];
            CGFloat dy = scrollView.contentOffset.y + scrollView.height - scrollView.contentSize.height;
            self.contentMenuView.y = self.view.height - self.contentMenuView.height - dy;
            if (dy <= self.contentMenuView.height) {
                self.contentMenuMaskView.y = dy;
                self.contentMenuMaskView.height = self.contentMenuView.height - dy;
            } else {
                //防止menuview上升一部分后突然往上拉,上升高度大于menuview的高度,height還沒變成0,所以需要設成0;
                if (self.contentMenuMaskView.height != 0) {
                    self.contentMenuMaskView.height = 0;
                }
            }

        } else {
            self.scrollView.backgroundColor = [UIColor groupTableViewBackgroundColor];
            //這個是boss直聘的bug
            //防止從底下往上拉時,突然一下下來,因為沒有過渡,所以contentMenuView的坐標還在上面,所以需要重置下
            CGFloat originContentMenuY = self.view.height - self.contentMenuView.height;
            if (self.contentMenuView.y != originContentMenuY) {
                self.contentMenuView.y = originContentMenuY;
                self.contentMenuMaskView.y = 0;
                self.contentMenuMaskView.height = self.contentMenuView.height;
            }
        }
        
    }
}

這個demo還有一些比如

  • UIViewControllerAnimatedTransitioning的用法,用來定制轉場效果,實現demo中縮小tabbarcontroller的效果;
  • 還有一些keyframe動畫,組合動畫的應用;
  • 還有scrollview的用法,只用一個tableview進行切換;

以上這些就不在這里講了,可以直接看代碼,注釋很詳細;

如果覺得寫的還可以,幫忙star一下,謝謝~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,241評論 4 61
  • 丁小強閱讀 158評論 0 0
  • 1.每個網站的請求數據的格式基本一致,不可能一會json格式,一會xml格式。所以可以通過這點固定每個爬蟲的請求格...
    薛云龍閱讀 199評論 0 0
  • 突然想去一個陌生的地方。誰也不認識誰。一切空白。如果可以放下所有包袱。所有人都是新面孔。依然可以懵懂無知,帶著好奇...
    趕風閱讀 337評論 0 0
  • 感覺全都是變量,實驗陷入泥潭。抓不住主要矛盾。 勸自己要有耐心,相信沒有解決不了的問題。
    ritaxqzhang閱讀 200評論 0 0