一款滾動菜單的實(shí)現(xiàn)

滾動菜單是app展示數(shù)據(jù)常用的控件,使用頻率極高钻心,實(shí)現(xiàn)的過程就是對UIScrollView的應(yīng)用旦委,大體都是頂部一個標(biāo)題滾動視圖,下邊一個用來鋪顯示數(shù)據(jù)的View的滾動視圖朴则,然后實(shí)現(xiàn)聯(lián)動效果权纤,基本差不多了。

需求分析

  • 從筆者安裝的應(yīng)用上觀察乌妒,大體要實(shí)現(xiàn)功能標(biāo)題下劃線自適應(yīng)汹想,菜單的半透明左右的不同按鈕(參考優(yōu)酷撤蚊,網(wǎng)易云音樂)古掏。
屏幕快照 2016-10-11 10.31.31.png
屏幕快照 2016-10-11 10.26.41.png

屏幕快照 2016-10-11 10.26.53.png

實(shí)現(xiàn)

  • 總思想
    將標(biāo)題視圖,展示數(shù)據(jù)的視圖放到一個View 上,View 來管理不同的子視圖的滑動侦啸,子視圖由各自的控制管理槽唾,要做的就是封裝好這個視圖,名字就叫HYPageView光涂。

屏幕快照 2016-10-11 10.53.26.png

簡單的說就是把控制器的View放到scrollView,滑到某一頁庞萍,就加載某一頁的控制器,并且將控制器的View放到這一頁忘闻。需要注意的是钝计,創(chuàng)建的控制器必需要強(qiáng)引用,因?yàn)榫植孔兞繒?dǎo)致"控制器死掉"造成控制器里邊所有事件無法響應(yīng)齐佳,比如tabView沒有Cell私恬,Button點(diǎn)上去沒反應(yīng)等等,都是因?yàn)榭刂破鲝膬?nèi)存釋放了炼吴。

  • 下劃線自適應(yīng)
HYPageView00.gif

就是一邊滑本鸣,一邊動,根據(jù)當(dāng)前滑動的位置改變線條的位置硅蹦,線條的長度也總是趨于下一個位置的長度荣德,這種很細(xì)節(jié)的東西吸引了筆者闷煤,如何實(shí)現(xiàn)呢?

需要計算兩點(diǎn)位置命爬,長度曹傀;

  • 方法1(坑)
    首先想到是 計算相對偏移量,我們總是能知道當(dāng)前位置和下一個位置饲宛,只要計算線條位置相對與手指拖拽的位置的偏移量,通過加減就可以算出準(zhǔn)確的位置嗜价,線條的長度一個道理艇抠。感覺有點(diǎn)麻煩,但我嘗試的這么做了久锥。
    在UIScrollViewDelegate 里的scrollViewDidScroll 方法中算出并記錄每一次偏移量家淤,然后累計到下劃線上,結(jié)果是效果差不多瑟由。但總是有誤差絮重,誤差的原因是誤差累計,與越界歹苦,前者是在計算的過程精度的丟失青伤,多次累加產(chǎn)生的誤差,后者是在滑動的過程殴瘦,結(jié)束的位置不會保證是下一個位置的結(jié)束點(diǎn)狠角,我也嘗試的修復(fù)這種誤差,但滑的越快誤差就越大蚪腋。然后我就嘗試尋找更好的方法丰歌。

找到了一個例子,和方法1的坑一毛一樣
傳送門??快速集成App中頂部標(biāo)題滾動條

反例1.gif

越來長的原因:可能是越界的問題屉凯,從圖中可以看出立帖,在返回自身位置時是一個累減的過程,而返回的最后一段距離終點(diǎn)不一定恰好是零界點(diǎn)悠砚,這段長度可能沒有減去晓勇,拖著不放,誤差越來越大哩簿。從圖中也可以看出作者在結(jié)束滾動時對線條進(jìn)行了校正宵蕉。

  • 方法2
    想要精確無誤,就想到了利用數(shù)學(xué)的知識來解決节榜,通過觀察想到了contentOffset 的值與線條點(diǎn)的位置唯一對應(yīng)羡玛,也就是說線條點(diǎn)的位置是關(guān)于contentOffset的一個函數(shù),不難發(fā)現(xiàn)就是一個分段函數(shù)宗苍,而且每一段都是一個 一次函數(shù) 形如y=kx+b 這里x 是 contentOffset 稼稿,y 是 線條的點(diǎn)或長度薄榛,寫一個方法,傳入contentOffset返回點(diǎn)的位置或線條的寬度让歼,顯然要一組k與b敞恋,而k 與 b 在 構(gòu)造標(biāo)題位置的就可以計算出來 k = △y/△x ,得到k后b也可以得到谋右。
    然后在- (void)scrollViewDidScroll:(UIScrollView *)scrollView;方法里只有兩行代碼
_lineBottom.center = CGPointMake([self getTitleWidth:scrollView.contentOffset.x], _lineBottom.center.y);
_lineBottom.bounds = CGRectMake(0, 0, [self getTitlePoint:scrollView.contentOffset.x], LINEBOTTOM_HEIGHT);

計算的代碼

#pragma mark - Calculation Method

- (CGFloat)getTitleWidth:(CGFloat)offset{
    NSInteger index = (NSInteger)(offset / _selfFrame.size.width);
    CGFloat k = [_width_k_array[index] floatValue];
    CGFloat b = [_width_b_array[index] floatValue];
    CGFloat x = offset;
    return  k * x + b;
}
- (CGFloat)getTitlePoint:(CGFloat)offset{
    NSInteger index = (NSInteger)(offset / _selfFrame.size.width);
    CGFloat k = [_point_k_array[index] floatValue];
    CGFloat b = [_point_b_array[index] floatValue];
    CGFloat x = offset;
    return  k * x + b;
}

這樣就達(dá)到完美的線條自適應(yīng)效果如下:

HYPageView03.gif
HYPageView08.gif
  • 菜單的半透明
    菜單的半透明很簡單硬猫,設(shè)置好ScrollView的contentInset和frame就好了,需要注意的是有navigationController時控制器的automaticallyAdjustsScrollViewInsets 屬性 和 edgesForExtendedLayout屬性在開啟navigationBar 半透明效果時 navigationController會對 控制器的 contentInset 和 frame進(jìn)行調(diào)整 以達(dá)到半透明效果改执。
  • 左右的不同按鈕
    前邊的步驟做好了這里也很簡單啸蜜,設(shè)計可以根據(jù)navigationBar 的左右item來設(shè)計。筆者直接添加Button然后重新計算頂部菜單滾動視圖的寬辈挂,效果如下:
HYPageView05.gif
HYPageView06.gif
  • 接口的設(shè)計
/**
 Initializes and returns a newly allocated view object with the specified frame rectangle.
 
 @param frame       ...
 @param titles      Some title
 @param controllers Name of some controllers
 @param parameters  You need to set a property called "parameter" for your controller to receive.

 @return self
 */
- (instancetype)initWithFrame:(CGRect)frame withTitles:(NSArray *)titles withViewControllers:(NSArray *)controllers withParameters:(NSArray *)parameters;

```
frame衬横,titles 不用說,controllers是傳控制器的名稱终蒂,這樣可以在需要的時候再創(chuàng)建控制器蜂林,parameters是要給控制器傳的參數(shù),傳遞的方式是KVC,當(dāng)然傳遞的時候需要檢查參數(shù)是否存在拇泣,控制器是否有parameters參數(shù)噪叙,具體實(shí)現(xiàn)可以看demo。
https://github.com/runlhy/HYPageView
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末挫酿,一起剝皮案震驚了整個濱河市构眯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌早龟,老刑警劉巖惫霸,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異葱弟,居然都是意外死亡壹店,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門芝加,熙熙樓的掌柜王于貴愁眉苦臉地迎上來硅卢,“玉大人,你說我怎么就攤上這事藏杖〗埽” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵蝌麸,是天一觀的道長点寥。 經(jīng)常有香客問我,道長来吩,這世上最難降的妖魔是什么敢辩? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任蔽莱,我火速辦了婚禮,結(jié)果婚禮上戚长,老公的妹妹穿的比我還像新娘盗冷。我一直安慰自己,他們只是感情好同廉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布仪糖。 她就那樣靜靜地躺著,像睡著了一般迫肖。 火紅的嫁衣襯著肌膚如雪乓诽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天咒程,我揣著相機(jī)與錄音,去河邊找鬼讼育。 笑死帐姻,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的奶段。 我是一名探鬼主播饥瓷,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼痹籍!你這毒婦竟也來了呢铆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蹲缠,失蹤者是張志新(化名)和其女友劉穎棺克,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體线定,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡娜谊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了斤讥。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纱皆。...
    茶點(diǎn)故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖芭商,靈堂內(nèi)的尸體忽然破棺而出派草,到底是詐尸還是另有隱情,我是刑警寧澤铛楣,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布近迁,位于F島的核電站,受9級特大地震影響蛉艾,放射性物質(zhì)發(fā)生泄漏钳踊。R本人自食惡果不足惜衷敌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拓瞪。 院中可真熱鬧缴罗,春花似錦、人聲如沸祭埂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛆橡。三九已至舌界,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間泰演,已是汗流浹背呻拌。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留睦焕,地道東北人藐握。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像垃喊,于是被迫代替她去往敵國和親猾普。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評論 2 354

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