模擬京東商城實(shí)現(xiàn)導(dǎo)航條隱藏功能

樣式需求展示-京東導(dǎo)航條

:.gif
需求說明:

1.導(dǎo)航條隱藏功能
2.界面向上滾動(dòng)的時(shí)候,導(dǎo)航條隱藏
3.界面向下滾動(dòng)的時(shí)候,導(dǎo)航條顯示


層次結(jié)構(gòu)分析:

核心思路:導(dǎo)航條必須隱藏,顯示的頂部的類似于導(dǎo)航條的控件,是我們自定義的UIView,才能實(shí)現(xiàn)效果!

層級(jí)結(jié)構(gòu)分析:


1.png

思路①:使用圖中 - 原諒色的View - 導(dǎo)航條View - 替代navigationBar

==>問題出現(xiàn) - 這種整個(gè)導(dǎo)航條View隱藏的時(shí)候,頂部時(shí)間View也隱藏了!不符合要求

2.png

思路②.頂部分成三個(gè)模塊部分相互獨(dú)立:

  • 頂部時(shí)間工具條自己一個(gè)View
  • 導(dǎo)航條自己一個(gè)View
  • 按鈕VIew自己一個(gè)獨(dú)立的View
  • 內(nèi)容tableView自己獨(dú)立一個(gè)View就不用說了

隱藏導(dǎo)航條 && 界面移動(dòng)的原理解釋

①.界面上移的時(shí)候 - 導(dǎo)航View隱藏:

3.png
  • 原理色的導(dǎo)航條View隱藏
  • 按鈕View上移
  • tableView上移
  • tabView高度 ++ (加上導(dǎo)航條View的高度)

①.界面上移的時(shí)候 - 隱藏的導(dǎo)航View顯示:


4.png
  • 原理色的導(dǎo)航條View顯示
  • 按鈕View下移
  • tableView下移
  • tabView高度 -- (減去剛剛++的導(dǎo)航條View高度)

問題難點(diǎn):如果知道 下方的tableView滾動(dòng)方法(怎么知道是向上滾還是向下滾動(dòng))

思路1:tableVIew本質(zhì)是scrollview,判斷scrollview的滾動(dòng)方向,通過contentOffset

思路2:

使用KVO,監(jiān)聽tableVIew的滾動(dòng),監(jiān)聽兩個(gè)值 - NSKeyValueObservingOptionOld && NSKeyValueObservingOptionNew,通過新舊值的 .y值,判斷滾動(dòng)方向。

這里使用的就是思路2的方法:

a.隱藏系統(tǒng)默認(rèn)的導(dǎo)航條View,然后自定義和導(dǎo)航條一模一樣的UIView上去
[self.navigationController setNavigationBarHidden:YES];

b.tableView添加KVO監(jiān)聽滑動(dòng)方向
[_tableView addObserver:self forKeyPath:NSStringFromSelector(@selector(contentOffset)) options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];

c.通過觀察者監(jiān)聽值的變化

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    CGFloat oldOffsetY = [change[NSKeyValueChangeOldKey] CGPointValue].y;
    CGFloat newOffsetY = [change[NSKeyValueChangeNewKey] CGPointValue].y;
    CGFloat deltaY = newOffsetY - oldOffsetY;

    if(deltaY >= 0) { 
       //向上滾動(dòng)}
    else{
      //向下滾動(dòng)
}

c.在向上滾動(dòng)的時(shí)候 - 設(shè)置導(dǎo)航條隱藏 + View上移

    if(deltaY >= 0) {  //向上滾動(dòng)

        [UIView animateWithDuration:0.25 animations:^{
            
            //隱藏導(dǎo)航條
            _navigationView.hidden = YES;
            
            //按鈕View上移導(dǎo)航條View的高度 - Y值改變
            CGRect tempShowViewFrame =  _showView.frame;
            tempShowViewFrame.origin.y -= navigationBarH;
            _showView.frame = tempShowViewFrame;
            
             //tableView上移導(dǎo)航條View的高度 - Y值改變 && 高度 增加導(dǎo)航條的view的高度
            CGRect tempTableViewFrame = _tableView.frame;
            tempTableViewFrame.origin.y -= navigationBarH;
            tempTableViewFrame.size.height += navigationBarH;
            _tableView.frame = tempTableViewFrame;
            
        }];
        
    }

d.在界面向下滾動(dòng)的時(shí)候 - 設(shè)置導(dǎo)航條View顯示 + View下移

    else {
        //向下滾動(dòng) - show
        [UIView animateWithDuration:0.25 animations:^{
            
            _navigationView.hidden = NO;
            
            CGRect tempShowViewFrame =  _showView.frame;
            tempShowViewFrame.origin.y += navigationBarH;
            _showView.frame = tempShowViewFrame;
            
            CGRect tempTableViewFrame = _tableView.frame;
            tempTableViewFrame.origin.y += navigationBarH;
            tempTableViewFrame.size.height -= navigationBarH;
            _tableView.frame = tempTableViewFrame;
            
        }];
    }

核心代碼如上,其實(shí)本質(zhì)就是通過KVO觀察tableView的滾動(dòng)方向,然后設(shè)置對(duì)應(yīng)的View顯示 && 位置變化

Demo展示:


singleVC.gif



進(jìn)階篇:跨控制器改變View的顯示


demo中的View都在同一個(gè)界面,可以直接在observeValueForKeyPath方法中,直接通過 UIView的成員變量改View的狀態(tài),但是如果跨控制器呢?

complexVC.gif

如圖:此界面的頂部三個(gè)按鈕,分別對(duì)應(yīng)響應(yīng)的三個(gè)控制器[‘全部’,‘測(cè)試1’,‘測(cè)試2’],控制器結(jié)構(gòu)分析:


5.png
  • 導(dǎo)航View && 按鈕View && 按鈕在外層的控制器上
  • 每個(gè)按鈕對(duì)應(yīng)各自的單獨(dú)一個(gè)控制器,顯示內(nèi)容
  • 按鈕對(duì)應(yīng)的內(nèi)部VC的view 添加到外層的VC的View上,才能得到顯示
  • 最終顯示的tableView,其實(shí)是按鈕VC里面的- [btn->內(nèi)部VC的view addsubView:tableVIew]
  • 所以簡(jiǎn)單的說,就是tableVIew和其他的View不在同一個(gè)控制器里

思路:跨控制器傳值

(這里打算使用 - 代理模式)


==>思路:

  1. 因?yàn)槭峭ㄟ^tableView滾動(dòng)方向,判斷View的顯示隱藏 && 位置,所以判斷在tableView對(duì)應(yīng)的控制器上;
  2. 外部控制器根據(jù)tableView控制器的滾動(dòng)方向而做出相應(yīng)的變化,所以外部控制器要成為代理對(duì)象,協(xié)議聲明寫在tableView控制器上
  3. 外部控制要顯示還是隱藏,tableView控制器要告訴他,所以代理方法要傳值
//tableView控制器的.h文件
@protocol HZOrderNavigationViewDelegate <NSObject>

- (void)changeNavigationViewShow:(BOOL)hidden;
@end


tableView控制器,還是一樣通過KVO監(jiān)聽tableView的contentOffSet,然后在observeValueForKeyPath 方法中,由于無法直接控制外部VC的界面屬性,所以通過代理傳值,告訴外部控制器,界面要發(fā)生的變化

//tableView控制器的.m文件 
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    
    CGFloat oldOffsetY          = [change[NSKeyValueChangeOldKey] CGPointValue].y;
    CGFloat newOffsetY          = [change[NSKeyValueChangeNewKey] CGPointValue].y;
    CGFloat deltaY              = newOffsetY - oldOffsetY;
    if(deltaY >= 0) {  //向上滾動(dòng)
        //變成執(zhí)行代理方法,通知外部VC的界面發(fā)生改變
        if ([_delegate respondsToSelector:@selector(changeNavigationViewShow:)]) {
            
            [_delegate changeNavigationViewShow:YES];
        }
}
//外部控制器接收到tableView控制器傳來的值之后,做出的界面改變
-(void)changeNavigationViewShow:(BOOL)hidden{
    
    if (hidden) {
        //導(dǎo)航條隱藏
        [UIView animateWithDuration:0.25 animations:^{
            
            _navigationView.hidden = YES;
            //按鈕View位置改變
            CGRect tempShowViewFrame =  _topBtnsView.frame;
            tempShowViewFrame.origin.y -= navigationBarH;
            _topBtnsView.frame = tempShowViewFrame;
            
            //修改scrollview - 按鈕VC對(duì)應(yīng)的view添加到這個(gè)scrollview上的
            CGRect tempScrollViewFrame = _contentScrollView.frame;
            tempScrollViewFrame.origin.y -= navigationBarH;
            tempScrollViewFrame.size.height += navigationBarH;
            _contentScrollView.frame = tempScrollViewFrame;
        }];

    }

原理其實(shí)和同一個(gè)控制器里面改變UIView的屬性一樣,只是這里跨了控制器,無法拿到屬性,所以是通過代理傳值告訴外部的那個(gè)控制器做出相應(yīng)的改變而已,本質(zhì)核心不變。


幾個(gè)小細(xì)節(jié):

  • 細(xì)節(jié)1:
7.png
8.png

所以界面變化的步驟應(yīng)該如下:

  1. 導(dǎo)航View隱藏
  2. 按鈕View上移
  3. 外層scrollview上移,高度 ++
  4. tableView要和scrollview一樣高度++,但是Y不用移動(dòng)!!

  • 細(xì)節(jié)2:判斷界面的顯示or隱藏,如果導(dǎo)航條View已經(jīng)隱藏了,再怎么上拉,也不能再調(diào)用使界面再次隱藏的辦法,同時(shí)不能再讓下方兩個(gè)View的Y值 --;
bug1.gif

如圖所示,要添加判斷,如果導(dǎo)航條已經(jīng)隱藏了,按鈕View 和 tableView就不要再一直往上跑了,最多就上移一個(gè)View的位置就夠了,所以要添加判斷;

如果是在同一個(gè)控制器中,可以添加 - _navigationView.hidden 屬性判斷

   if(deltaY >= 0) {  //向上滾動(dòng)
       NSLog(@"向上滾動(dòng) - hidden");
       if (_navigationView.hidden == YES) {
           return;
       }

但是這里是跨控制器的,_navigationView屬性是在外部控制器上,而不是在tableView的控制器上,所以拿不到!

  • 根據(jù)y值判斷?


    6.png
9.png

問題出現(xiàn):tableView是添加到外部控制的內(nèi)容ScrollView上的,Y值永遠(yuǎn)是0!所以不能用y值判斷!

10.png

解決辦法:Y值雖然是0無法進(jìn)行判斷,但是可以通過tableView的高度進(jìn)行判斷!

  if(deltaY >= 0) {  //向上滾動(dòng)
        
        if (_tableView.frame.size.height == ScreenH - (topTimeToolH + CarInsOrderTopViewH )) {
           //說明tableView上方?jīng)]有導(dǎo)航條View  - 導(dǎo)航條已經(jīng)隱藏了,此時(shí)上滾就不用再改變位置了
            return;
        }

同理:向下滾動(dòng)的時(shí)候也要添加判斷

    else{
        if (_tableView.frame.size.height == ScreenH - (topTimeToolH + CarInsOrderTopViewH + navigationBarH))   return;
        }

  • 細(xì)節(jié)3:判斷的值最好不要用0,不然稍微一碰tableView,界面就發(fā)生變化
    if(deltaY >= 50) {  //向上滾動(dòng)
}
    else if (deltaY <= -50){
}


進(jìn)階 - 下拉刷新導(dǎo)致的Bug

下拉刷新Bug.gif

bug說明:如圖,只要一使用下拉刷新,就自動(dòng)調(diào)用 - 導(dǎo)航條View隱藏 并且 外部控制器上移效果

下拉刷新的時(shí)候,本質(zhì)上也是拖動(dòng)tableView,一樣會(huì)進(jìn)tableView的監(jiān)聽方法!


項(xiàng)目需求:下拉刷新的時(shí)候,不要和gif顯示的一樣,導(dǎo)致導(dǎo)航條隱藏并使得界面上移!

解決方案 :


11.png

如圖,我們發(fā)現(xiàn),下拉的時(shí)候,跑出來的 mj_headerView - 高度54,就等于,直接讓tableView的contentOffset.y = 54了!

解決如下:所以要進(jìn)代理方法,判斷y的位移量,一定要大于54!大于54才讓進(jìn)入代理方法,例如取個(gè)80,否則每次下拉刷新都會(huì)進(jìn)入代理方法改變界面


    if(deltaY >= 80) {  //向上滾動(dòng)
        
        if (_tableView.frame.size.height == ScreenH - (topTimeToolH + CarInsOrderTopViewH )) {
            return;
        }

最終效果演示:


解決下拉刷新Bug.gif

demo地址~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,125評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,506評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,402評(píng)論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,934評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,168評(píng)論 0 287
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,690評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,596評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,784評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評(píng)論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,027評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評(píng)論 1 280
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,398評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,743評(píng)論 2 370

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,147評(píng)論 4 61
  • 記起了曾經(jīng) 許下的誓言 陪我度過 漫漫的冬季 濕潤(rùn)的眼角 敵不過汝心 是不是風(fēng)雨 還沒到盡頭 你總是對(duì)我說 讓我不...
    木木MY閱讀 424評(píng)論 2 4
  • 金波一旋若太陰, 銀面百媚實(shí)可憐。 峻嶺逶迤鳥絕飛, 天地遼闊書難傳。 1983.2.4夜
    果州聞郡閱讀 229評(píng)論 0 0
  • 幸福是更多的金錢嗎?是擁有更多的權(quán)力嗎?是成為明星嗎?是傾城之貌或曼妙身姿?當(dāng)然這些可以為幸福加分但絕不是幸福的必...
    沐陽燕閱讀 460評(píng)論 0 0