仿微博滾動(dòng)視圖嵌套的手勢(shì)處理

現(xiàn)在上市場(chǎng)上很多主流的App模塊都是很龐大榨汤,往往一個(gè)頁(yè)面會(huì)有很復(fù)雜的功能惶楼,但是再大的模塊都是由一個(gè)個(gè)簡(jiǎn)單的模塊堆疊起來(lái)的。模塊多了之后疼燥,有時(shí)要處理好模塊之間的聯(lián)系不是那種想都不用想就可以開(kāi)干的沧卢。還涉及到不同模塊之間的手勢(shì)和動(dòng)畫(huà)處理。

為了舉個(gè)比較好的栗子醉者,就拿微博個(gè)人信息界面動(dòng)動(dòng)手但狭。通過(guò)觀察微博個(gè)人信息界面,總結(jié)出需要注意的三個(gè)地方:

  1. 頭部背景圖滾動(dòng)處理
  2. 兩層滾動(dòng)視圖嵌套手勢(shì)處理
  3. 按鈕底部毛毛蟲(chóng)動(dòng)畫(huà)效果

頭部背景

先看下效果圖

scroll.gif

首先第一步分析 頂部的ImageView撬即,如果手勢(shì)向上滾動(dòng)我們會(huì)發(fā)現(xiàn)它就和 TableHeaderView差不多立磁,當(dāng)向下拉伸直到TableView出現(xiàn)彈性效果的時(shí)候,頭部的ImageView變高了剥槐,但是不是放大唱歧。而頭像是保持不動(dòng)的。因此,頂部ImageView不是TableHeaderView颅崩,它的坐標(biāo)會(huì)隨著TableView滾動(dòng)作出不同的改變几于。它的位置是在TableView下面,設(shè)置tableHeaderView為透明即可沿后。
scrollViewDidScroll:代理函數(shù)中實(shí)現(xiàn)(-60是它的初始y坐標(biāo))

 if(offsetY <= 0){
        self.coverView.y = -offsetY/2 + (- 60);
    }else{
        self.coverView.y = -offsetY + (- 60);
    }

多重嵌套

實(shí)現(xiàn)這個(gè)布局可以是實(shí)現(xiàn)一個(gè)TabView沿彭,把四個(gè)子視圖作為T(mén)abView的子控件, TabView作為TableView的cell顯示出來(lái)尖滚。但是當(dāng)我們照做的時(shí)候發(fā)現(xiàn)喉刘,當(dāng)滾動(dòng)TableView到底部的時(shí)候,TabView的子視圖不會(huì)滾動(dòng)漆弄,而滾動(dòng)TabView的子視圖到頂部睦裳,TableView也不會(huì)滾動(dòng)。之所以會(huì)出現(xiàn)這樣的情況是因?yàn)樽涌丶透缚丶謩?shì)是單獨(dú)響應(yīng)不會(huì)傳遞撼唾。解決的方法是自定義一個(gè)UITableView重寫(xiě)以下方法

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    return YES;
}

這個(gè)方法返回YES可以讓子控件接收到父控件的手勢(shì)事件廉邑,子控件的手勢(shì)也會(huì)傳給父控件,在這里可以讓UITableView的滾動(dòng)事件傳遞倒谷。

但是實(shí)現(xiàn)后發(fā)現(xiàn) 滾動(dòng)四個(gè)子控件 父控件也跟著滾動(dòng)鬓催。我們要實(shí)現(xiàn)的是:當(dāng)父控件滾動(dòng)到底部時(shí)子控件才能滾動(dòng),子控件滾動(dòng)到頭部時(shí)恨锚,子控件停止?jié)L動(dòng)父控件開(kāi)始滾動(dòng)。邏輯代碼如下:

父控件:

 if(offsetY >= HeaderHeight - 64){
       [[NSNotificationCenter defaultCenter] postNotificationName:TabViewScrollToTopNotification object:@(YES)];
        self.shouldScroll = NO;
    }else{
        [[NSNotificationCenter defaultCenter] postNotificationName:TabViewScrollToTopNotification object:@(NO)];
    }
    if(self.shouldScroll == NO){
     [scrollView setContentOffset:CGPointMake(0, HeaderHeight - 64)];
    }

子控件:

  CGFloat offsetY = scrollView.contentOffset.y;
    if(offsetY <= 0){
        [[NSNotificationCenter defaultCenter]  postNotificationName:ItemScrollToTopNotification object:@(YES)];
    }
    if(self.shouldScroll  == NO){
        [scrollView setContentOffset:CGPointZero];
    }

毛毛蟲(chóng)效果

實(shí)現(xiàn)毛毛蟲(chóng)動(dòng)畫(huà)效果可有多種方式倍靡,在這里我用的是CASharpLayer結(jié)合UIBezierPath來(lái)實(shí)現(xiàn)猴伶。

仔細(xì)觀察動(dòng)畫(huà)可發(fā)現(xiàn),動(dòng)畫(huà)可以切分為兩部完成塌西,如下圖所示:

line.png

通過(guò)改變 CASharpLayerstrokeStartstrokeEnd屬性來(lái)控制長(zhǎng)度即可他挎。

首先, 在初始化布局每個(gè)標(biāo)題按鈕的時(shí)候捡需,用一個(gè)字典把所有按鈕下面的坐標(biāo)記錄下來(lái)

- (void)setupBtn:(UIButton *)btn index:(NSInteger)index{
    if(index == 0){
        btn.selected = YES;
        self.selectBtn = btn;
    }
    self.btnDict[@(index)] = btn;
    self.pointsDict[@(index)] = @{@"start":@(btn.x + 2),@"end":@(CGRectGetMaxX(btn.frame)-2)};
    btn.tag = index;
  /**
  .  其他設(shè)置
     ......
   */
}

然后通過(guò)監(jiān)控scrollView的偏移量办桨,結(jié)合保存的坐標(biāo)計(jì)算出在不同位置的下標(biāo)線(xiàn)的strokeStart和strokeEnd

- (void)LHTabViewDidScroll:(LHTabView *)tabView{
    CGFloat offsetX = tabView.offset.x;
    NSInteger index = offsetX/WIDTH;
    CGFloat zero =  [self.pointsDict[@(0)][@"start"] floatValue];
    CGFloat currentStart =  [self.pointsDict[@(index)][@"start"] floatValue];
    CGFloat currentEnd =  [self.pointsDict[@(index)][@"end"] floatValue];
    CGFloat nextStart =  [self.pointsDict[@(index+1)][@"start"] floatValue];
    CGFloat nextEnd =  [self.pointsDict[@(index+1)][@"end"] floatValue];
    CGFloat PhysicsDelta = offsetX - index * WIDTH;
    CGFloat end,start;
    CGFloat delta = nextEnd - currentEnd;
    if(PhysicsDelta <= WIDTH/2){ //對(duì)應(yīng)圖片 step one
        delta = (PhysicsDelta/(WIDTH/2)) * delta;
        end = currentEnd + delta;
        self.lineLayer.strokeStart = (currentStart - zero)/self.lineTotalWidth;
        self.lineLayer.strokeEnd = (end - zero)/self.lineTotalWidth;
    }else{ //對(duì)應(yīng)圖片 step two
        delta = nextStart - currentStart;
        PhysicsDelta = PhysicsDelta - WIDTH/2;
        delta = (PhysicsDelta/(WIDTH/2)) * delta;
        start = currentStart + delta;
        self.lineLayer.strokeStart = (start - zero)/self.lineTotalWidth;
        self.lineLayer.strokeEnd = (nextEnd - zero)/self.lineTotalWidth;
    }
}

剛開(kāi)始的時(shí)候發(fā)現(xiàn)CAShaplayer滑動(dòng)的效果和scrollView的滑動(dòng)有延遲,可以通過(guò)CAShaplayer的speed屬性來(lái)調(diào)整動(dòng)畫(huà)速率即可 站辉。
實(shí)現(xiàn)效果圖如下:

animate.gif

以上就是所有的步驟呢撞。具體代碼可以點(diǎn)擊demo

最后吐槽下,因?yàn)樽罱谑褂?a target="_blank" rel="nofollow">react-native做一個(gè)項(xiàng)目饰剥,需要實(shí)現(xiàn)類(lèi)似功能殊霞,但是因?yàn)榛瑒?dòng)的效果沒(méi)有原生的流暢,出現(xiàn)很奇怪的現(xiàn)象汰蓉,各種不順绷蹲,沒(méi)辦法只能放棄使用這種UI結(jié)構(gòu)。看來(lái)react-native還有很長(zhǎng)的路要走祝钢,原生還是第一生產(chǎn)力比规。

原文鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市拦英,隨后出現(xiàn)的幾起案子蜒什,更是在濱河造成了極大的恐慌,老刑警劉巖龄章,帶你破解...
    沈念sama閱讀 206,013評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吃谣,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡做裙,警方通過(guò)查閱死者的電腦和手機(jī)岗憋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)锚贱,“玉大人仔戈,你說(shuō)我怎么就攤上這事∨±龋” “怎么了监徘?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,370評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)吧碾。 經(jīng)常有香客問(wèn)我凰盔,道長(zhǎng),這世上最難降的妖魔是什么倦春? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,168評(píng)論 1 278
  • 正文 為了忘掉前任户敬,我火速辦了婚禮,結(jié)果婚禮上睁本,老公的妹妹穿的比我還像新娘尿庐。我一直安慰自己,他們只是感情好呢堰,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布抄瑟。 她就那樣靜靜地躺著,像睡著了一般枉疼。 火紅的嫁衣襯著肌膚如雪皮假。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 48,954評(píng)論 1 283
  • 那天骂维,我揣著相機(jī)與錄音钞翔,去河邊找鬼。 笑死席舍,一個(gè)胖子當(dāng)著我的面吹牛布轿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,271評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼汰扭,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼稠肘!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起萝毛,我...
    開(kāi)封第一講書(shū)人閱讀 36,916評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤项阴,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后笆包,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體环揽,經(jīng)...
    沈念sama閱讀 43,382評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評(píng)論 2 323
  • 正文 我和宋清朗相戀三年庵佣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了歉胶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,989評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡巴粪,死狀恐怖通今,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肛根,我是刑警寧澤辫塌,帶...
    沈念sama閱讀 33,624評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站派哲,受9級(jí)特大地震影響臼氨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜芭届,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評(píng)論 3 307
  • 文/蒙蒙 一一也、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧喉脖,春花似錦、人聲如沸抑月。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,199評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)谦絮。三九已至题诵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間层皱,已是汗流浹背性锭。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,418評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留叫胖,地道東北人草冈。 一個(gè)月前我還...
    沈念sama閱讀 45,401評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親怎棱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子哩俭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評(píng)論 2 345

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