Github
倉庫地址 如果你喜歡甲锡,記得點顆??喲
前言
伴隨著APP不斷迭代更新,各種功能也是越堆越多羽戒。對于用戶來說缤沦,在個人資料頁面需要顯示的元素也越來越多。如何井然有序的展示且交互簡單易稠,變成了一個難事缸废。當(dāng)然這一點也難不倒產(chǎn)品經(jīng)理,他們總會想出各種奇淫怪術(shù)來折磨我們(程序員)驶社。下面以簡書和微博來解讀下主流APP是如何處理的企量。
簡書&微博
正如上圖所示,簡書和微博的布局如出一轍亡电。一個TableHeaderView顯示背景圖届巩、頭像、簡介等基礎(chǔ)信息份乒。然后有一個SectionHeaderView恕汇,承載不同的內(nèi)容分類指引(動態(tài)腕唧、文章、更多等)瘾英,可以懸浮在頂部枣接。然后就是不同分類的數(shù)據(jù)流的TableView,可以直接滾動缺谴。建議大家打開簡書和微博但惶,把玩一下。
第一眼看上去湿蛔,感覺沒有什么難度嘛膀曾,就是一個主TableView嵌套一個ScrollView,支持左右滾動切換煌集,然后ScrollView放三個TableView妓肢。但是仔細思考會有許多難點需要解決,比如主TableView和嵌套TableView的手勢沖突苫纤,三個子TableView的位置更新等碉钠。
如果要自己解決這些問題,且要調(diào)試到目標(biāo)效果卷拘,可能要花上你大半天時間了喊废。而且本身個人資料頁面的業(yè)務(wù)邏輯就特別多,如果還要插入這種頁面交互邏輯栗弟,說實話污筷,當(dāng)你看到許多零散的代碼交織在一起時,你的頭會和足球一樣大UШ铡0曛!
所以這篇文章不會著重講解如何解決上面的問題(可以查看源碼分析)雷厂,而是將頁面結(jié)構(gòu)封裝好惋增,你只需要花一分鐘填充你的業(yè)務(wù)邏輯即可。媽媽再也不用擔(dān)心我去調(diào)試頁面交互邏輯了??
核心原理
讓滑動手勢給每個ScrollView都可以處理改鲫,只是對于mainTableView和listView有不同的邏輯
class JXUserProfileMainTableView: UITableView, UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return gestureRecognizer.isKind(of: UIPanGestureRecognizer.classForCoder()) && otherGestureRecognizer.isKind(of: UIPanGestureRecognizer.classForCoder())
}
}
- 對于mainTableView的滾動事件處理
func scrollViewDidScroll(_ scrollView: UIScrollView) {
self.delegate.mainTableViewDidScroll?(scrollView)
if (self.listItemScrollView != nil && self.listItemScrollView!.contentOffset.y > 0) {
//mainTableView的header已經(jīng)滾動不見诈皿,開始滾動某一個listView,那么固定mainTableView的contentOffset像棘,讓其不動
self.mainTableView.contentOffset = CGPoint(x: 0, y: self.delegate.tableHeaderViewHeight(in: self))
}
if (scrollView.contentOffset.y < self.delegate.tableHeaderViewHeight(in: self)) {
//mainTableView已經(jīng)顯示了header稽亏,listView的contentOffset需要重置
for index in 0..<self.delegate.numberOfListViews(in: self) {
let listView = self.delegate.userProfileView(self, listViewInRow: index)
listView.scrollView.contentOffset = CGPoint.zero
}
}
}
- 對于listView的滾動事件處理
/// 外部傳入的listView,當(dāng)其內(nèi)部的scrollView滾動時缕题,需要調(diào)用該方法
open func listViewDidScroll(scrollView: UIScrollView) {
self.listItemScrollView = scrollView
if (self.mainTableView.contentOffset.y < self.delegate.tableHeaderViewHeight(in: self)) {
//mainTableView的header還沒有消失截歉,讓listScrollView一直為0
scrollView.contentOffset = CGPoint.zero;
scrollView.showsVerticalScrollIndicator = false;
} else {
//mainTableView的header剛好消失,固定mainTableView的位置避除,顯示listScrollView的滾動條
self.mainTableView.contentOffset = CGPoint(x: 0, y: self.delegate.tableHeaderViewHeight(in: self));
scrollView.showsVerticalScrollIndicator = true;
}
}
實現(xiàn)效果
使用
1.實例化JXUserProfileView
userProfileView = JXUserProfileView(delegate: self)
userProfileView.delegate = self
self.view.addSubview(userProfileView)
2.實現(xiàn)JXUserProfileViewDelegate
@objc protocol JXUserProfileViewDelegate {
///mainTableView的滾動回調(diào)怎披,用于實現(xiàn)頭圖跟隨縮放
@objc optional func mainTableViewDidScroll(_ scrollView: UIScrollView)
///tableHeaderView的高度
func tableHeaderViewHeight(in userProfileView: JXUserProfileView) -> CGFloat
///返回tableHeaderView
func tableHeaderView(in userProfileView: JXUserProfileView) -> UIView
///heightForHeaderOfSection胸嘁,就是分類視圖的高度
func heightForHeaderOfSection(in userProfileView: JXUserProfileView) -> CGFloat
///viewForHeaderOfSection,分類視圖凉逛,我用的是自己封裝的JXCategoryView性宏,你也可以選擇其他的或者自己寫
func viewForHeaderOfSection(in userProfileView: JXUserProfileView) -> UIView
///底部listView的條數(shù)
func numberOfListViews(in userProfileView: JXUserProfileView) -> Int
///返回對應(yīng)index的listView,需要是UIView的子類状飞,且要遵循JXUserProfileListViewDelegate毫胜。這里要求返回一個UIView而不是一個UIScrollView,因為listView可能并不只是一個單純的TableView诬辈,還會有其他的元素
func userProfileView(_ userProfileView: JXUserProfileView, listViewInRow row: Int) -> JXUserProfileListViewDelegate & UIView
}
3.讓外部listView遵從JXUserProfileListViewDelegate
協(xié)議
//該協(xié)議主要用于mainTableView已經(jīng)顯示了header酵使,listView的contentOffset需要重置時,內(nèi)部需要訪問到外部傳入進來的listView內(nèi)的scrollView
@objc protocol JXUserProfileListViewDelegate {
var scrollView: UIScrollView { get }
}
4.將外部listView的滾動事件傳入userProfileView
func listViewDidScroll(_ scrollView: UIScrollView) {
userProfileView.listViewDidScroll(scrollView: scrollView)
}
不用一分鐘焙糟,就可以集成完畢??
Github
倉庫地址 如果你喜歡口渔,記得點顆??喲