這是一個類似半糖首頁、QQ音樂列表万皿、美麗說首頁摧找、格瓦斯電影詳情頁,既能上下滑動牢硅,同時用能左右滑動的控件慰于。項目地址GitHub
說起這個項目,還是得談一下一開始寫這個項目的緣由唤衫。前一陣子婆赠,公司項目首頁改版,要求作出半糖首頁的效果⌒堇铮看了一眼半糖之后蛆挫,心中一萬只草泥馬奔過,怎么會做這種設(shè)計妙黍?后來悴侵,想了一天的時間,終于把大概的實現(xiàn)原理捋順出來拭嫁,又花了幾天的時間來一步步的實現(xiàn)可免,解決bug。最后終于可以實現(xiàn)上下與左后滑動同時兼容的效果了做粤。由于只是首頁改版浇借,所以只是首頁實現(xiàn)了效果,也并沒有單獨寫一個控件怕品,可是妇垢,一周之后,悲劇的事發(fā)生了:新的產(chǎn)品設(shè)計中有幾個頁面都是這樣的設(shè)計肉康。好吧闯估,還是乖乖的寫個控件吧。于是吼和,就有了SwipeTableView涨薪。
先來幾張預覽吧:
再來說一下實現(xiàn)原理:
最初的設(shè)計并沒有考慮兼容第三方下拉刷新的問題,所以最初的設(shè)計更簡潔炫乓,擴展性也更好刚夺。下面是原理的結(jié)構(gòu)圖——?
1. 首先,為了實現(xiàn)左右滑動的功能厢岂,需要一個view來作為所有單一item的父視圖載體光督,并提供左右滑動的功能,這里沒有比`UICollectionView`再合適的了塔粒。所有结借,我用一個CollectionView作為contentView。
2. 有了CollectionView作為載體之后卒茬,就可以把每一個ScrollView作為CollectionView的item平鋪了船老。之后,最關(guān)鍵的問題圃酵,也是最難處理的問題柳畔,就是在滑動CollectionView的時候,怎樣保證前后item能夠?qū)R呢(因為懸停郭赐,只有對齊才行)薪韩?最后想到的解決辦法,就是在cellForItem的方法中,對前后兩個item的contentOffset進行adjust一致性調(diào)整俘陷。這樣能實現(xiàn)前后兩個item的位置是合理的罗捎。
3. 最后一個主要的問題就是,多個item共用一個header與bar的問題拉盾。既然共用桨菜,最后想到,那就讓header與bar與CollectionView一樣作為SwipeTableView的子視圖捉偏,并別在圖層最上面倒得。由于是獨立的view,之后就要解決當前item滑動同時滾動對header與bar做跟隨處理的問題了夭禽。在這里霞掺,對當前的item進行KVO,在item的contentOffset發(fā)生變化的時候驻粟,同樣改變header與bar的位置根悼,使之總是跟隨scrollview的滾動凶异,并在懸停的位置做判斷蜀撑,固定bar的frame的y值。
4. 這樣剩彬,基本的實現(xiàn)就完成了酷麦。同時,`SwipeTableView`允許自適應contentSize喉恋,就是在item的內(nèi)容很少的時候沃饶,也能自適應的調(diào)整contentSize,保整至少能夠滾動到頂端轻黑。5. 后期糊肤,用戶的反饋header不能滑動,最后通過`UIKitDynamic`物理引擎的方式解決了這個問題氓鄙。參考文章? 英文博客?
開源這個項目并沒有想會很多人使用馆揉,而后期,實際用到人越來越多抖拦,大家也都反映項目不能支持下拉刷新的問題升酣,所以,便有了第二種設(shè)計方式——?
在這個版本中态罪,跟上面的結(jié)構(gòu)原理是差不多的噩茄。由于header與bar是獨立的,那么每個item就要為header與bar的空間留出空白复颈。而在第一個設(shè)計中绩聘,是通過修改增加每個item contentInset的top值來留出頂部的留白。而幾乎所有的下拉刷新空間都是不考慮inset,直接設(shè)置在content的頂部的凿菩,而contentInset是不算內(nèi)容中的(一般下拉刷新控件rame的y值都是自身高度的負值)驯遇。所以,在添加了下拉刷新之后蓄髓,下拉刷新組件其實是藏在header與bar的下面的叉庐,底部也正好跟bar對齊(這里可以通過調(diào)整下拉刷新組件的frame,減小y值会喝,來顯露下拉組件即可)陡叠。為了方便使用,并且兼容第三方下拉刷新肢执,最后采用枉阵,每個item頂部的留白由tableHeaderVeiw代替(CollectionView方面要繼承`STCollectionView`設(shè)置collectionHeaderView)。不過這樣预茄,item的tableHeaderView就是占用的了兴溜,由于考慮項目的簡潔性,并沒有自定義`UIScrollView`支持scrollview設(shè)置headerview耻陕。這樣用戶完全可以只是通過設(shè)置一個宏就可以支持下拉刷新拙徽,更加方便
#define ST_PULLTOREFRESH_HEADER_HEIGHT xx
其中`xx`是指下拉刷新組件RefreshHeader的高度,也就是完全顯露RefreshHeader開始刷新的高度(如:`MJRefresh` 為 `MJRefreshHeaderHeight`诗宣,`SVPullToRefresh` 為 `SVPullToRefreshViewHeight`)膘怕。
最后在混合模式的時候出現(xiàn)了問題,最終發(fā)現(xiàn)召庞,原來`UICollectionView`不支持通過contentSize屬性來改變contentSize岛心。最后只好自定義`STCollectionView`,同時支持設(shè)置collectionHeaderView篮灼,也可以實現(xiàn)自適應contentSize忘古。關(guān)于`STCollectionView`的使用可以詳細看github示例。
而SwipeTableView的使用方式這里不做介紹了诅诱,有興趣的可以看看github的介紹髓堪。
總結(jié)
這是我的第一個比較完善的開源項目,在這個項目中逢艘,非常感謝使用者的認同與支持旦袋。通過這個項目,自己確實學到了很多東西它改,其實開這個博客也是源于這個項目的疤孕。個人覺得,對于開發(fā)者而言央拖,能夠參與一個項目祭阀,并去不斷的完善解決問題鹉戚,從中得到的受益將是非常大的。
最后专控,如果您也喜歡這個項目的話抹凳,非常歡迎您到GitHub?star或者fork,您的支持是對我的最大鼓勵??
2018.03.08 更新
由于 SwipeTableView 在對 IGListKit 支持上有些問題伦腐,同時對于 Item 都是 UICollectionView 的情況也不是友好赢底。所以,現(xiàn)在已經(jīng)開源了一個基于 UICollectionView 的新項目?HBHybridCollectionView柏蘑,實現(xiàn)效果類似好好住APP首頁幸冻。
我的Hexo博客地址,如有轉(zhuǎn)載請注明出處咳焚。