在網(wǎng)上看到一些寫新浪微博個人主頁的實(shí)現(xiàn)思路和代碼的文章,實(shí)際按他們的思路來做項(xiàng)目的時候發(fā)現(xiàn)有些效果跟真正的新浪微博不太一樣。特別是頭視圖與幾個subTableView的交互效果,比如有些demo的頭視圖無法實(shí)現(xiàn)懸停,有的demo頭視圖無法點(diǎn)擊響應(yīng)事件或者上下滾動,有些Demo無法左右滾動幾個subTableView的同時保持頭視圖不動。
后來經(jīng)過各種嘗試,終于自己在項(xiàng)目中將所有效果都實(shí)現(xiàn)了,現(xiàn)在把思路和代碼分享下。
一、頁面交互效果分析:
1.主頁面上下滑動時是在一個subTableView中滑動,左右滑動是切換到其他的subTableView;
2.有一個頭部headerView,無論哪個subTableView上下滑動,頭部視圖都會貼著隨之上下運(yùn)動,而且向下滾動到極限時帶彈性效果;左右滑動的時候subTableView時,headerView的位置固定不變;
3.headerView上滑時慢慢消失,露出導(dǎo)航欄,下拉時慢慢出現(xiàn),導(dǎo)航欄消失;header頭部視圖滑動到頂部時上面自帶的子菜單欄會懸停在導(dǎo)航欄下方;選擇子菜單欄能夠切換subTableView;
4.在headerView區(qū)域觸摸也可以上下滾動,效果和在subTableView上的滾動效果一模一樣;headerView區(qū)域有各種控件,點(diǎn)擊有事件響應(yīng);
5.如果headerView滾到最頂部即子菜單欄處于懸停狀態(tài),切換subTableView時,各subTableView的滾動位置不變;否則,滾動時第二個subTableView會自動滾動到頂部;
6.navigationBar和title的透明度效果變化:第一個使用的是動態(tài)添加透明度變化的backGroundImage,第二個是動態(tài)改變titleView的alpha
二、實(shí)現(xiàn)思路及主要代碼:
1.要想實(shí)現(xiàn)頁面中的subTableView手勢上下左右滾動效果,必然是要將幾個subTableView加載到一個水平方向滾動的horizontalScrollView上;
// 水平滾動的containScrollView
view.addSubview(containScrollView)
// 第1個tableView
let firstVC = HLProfileTableViewController.init(style: UITableViewStyle.grouped) firstVC.coverHeight = cacu_coverHeight + seperatorLineHeight containScrollView.addSubview(firstVC.view)
self.addChildViewController(firstVC)
// 第2個tableViewlet secondVC = HLWeiboTableViewController.init(style: UITableViewStyle.grouped) secondVC.coverHeight = cacu_coverHeight + seperatorLineHeight containScrollView.addSubview(secondVC.view) self.addChildViewController(secondVC)
// 第3個tableView let thirdVC = HLNewsTableViewController.init(style: UITableViewStyle.grouped) thirdVC.coverHeight = cacu_coverHeight + seperatorLineHeight containScrollView.addSubview(thirdVC.view)self.addChildViewController(thirdVC)
// 頭部視圖放在主視圖的最外面
view.addSubview(headerView)
headerView.frame = CGRect.init(x: 0, y: 0, width: ScreenW, height: headerHeight)
2.headerView的層級,根據(jù)它的UI交互方式,作為subTableView的子視圖的方式非常難以處理,這里是放在控制器主視圖的最外層。這樣subTableView水平滾動時它可以不會受影響;subTableView上下滾動的時候使用代理動態(tài)的調(diào)整headerView的高度即可;
var transform_y = scrollView.contentOffset.y
//tableView同步的滾動極限
let scrollLimit = cacu_coverHeight - switchMenuHeight + seperatorLineHeight if transform_y > scrollLimit {
transform_y = scrollLimit navigationController?.navigationBar.isTranslucent = false }else{ navigationController?.navigationBar.isTranslucent = true } navigationController?.navigationBar.setBackgroundImage(self.imageWithColor(color: UIColor.init(white:1 , alpha: transform_y/scrollLimit)), for: UIBarMetrics.default) titleLabel.textColor = UIColor.init(white:0 , alpha: transform_y/scrollLimit) // 因?yàn)橛袀€seperatorLine,所有scrollView的滾動范圍有可能小于帶上switchMenuHeight的總高度, if headerHeight - transform_y < switchMenuHeight + CYTStatusBarHeight + CYTNavigationBarHeightForSwi {// 如果滾到范圍到了小于switchMenuHeight高度的時候,headerView高度保持不變
headerView.frame = CGRect.init(x: 0, y: 0, width: ScreenW, height: switchMenuHeight + CYTStatusBarHeight + CYTNavigationBarHeightForSwi)
}else{headerView.frame = CGRect.init(x: 0, y: 0, width: ScreenW, height: headerHeight - transform_y)
}
3.headerView上的UI交互方式處理方式如下:使用HitTest方法進(jìn)行判斷,如果headerView的子視圖需要進(jìn)行UI交互,就讓該視圖接收手勢;否則就返回nil,也即是將手勢方法傳遞到headerView下面的tableView上,這樣headerView不點(diǎn)擊子視圖只是上下滾動就和直接滾動tableView效果一樣。代碼:
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
//需要交互的元素,點(diǎn)擊時觸發(fā)點(diǎn)擊響應(yīng)
for view in interactionItems {
if view.frame.contains(point){
return view
}
}
//點(diǎn)擊需要交互的元素以外的區(qū)域,不觸發(fā)點(diǎn)擊響應(yīng)
return nil
}