在网上看到一些写新浪微博个人主页的实现思路和代码的文章,实际按他们的思路来做项目的时候发现有些效果跟真正的新浪微博不太一样。特别是头视图与几个subTableView的交互效果,比如有些demo的头视图无法实现悬停,有的demo头视图无法点击响应事件或者上下滚动,有些Demo无法左右滚动几个subTableView的同时保持头视图不动。
后来经过各种尝试,终于自己在项目中将所有效果都实现了,现在把思路和代码分享下。
一、页面交互效果分析:
1.主页面上下滑动时是在一个subTableView中滑动,左右滑动是切换到其他的subTableView;
2.有一个头部headerView,无论哪个subTableView上下滑动,头部视图都会贴着随之上下运动,而且向下滚动到极限时带弹性效果;左右滑动的时候subTableView时,headerView的位置固定不变;
3.headerView上滑时慢慢消失,露出导航栏,下拉时慢慢出现,导航栏消失;header头部视图滑动到顶部时上面自带的子菜单栏会悬停在导航栏下方;选择子菜单栏能够切换subTableView;
image4.在headerView区域触摸也可以上下滚动,效果和在subTableView上的滚动效果一模一样;headerView区域有各种控件,点击有事件响应;
5.如果headerView滚到最顶部即子菜单栏处于悬停状态,切换subTableView时,各subTableView的滚动位置不变;否则,滚动时第二个subTableView会自动滚动到顶部;
image6.navigationBar和title的透明度效果变化:第一个使用的是动态添加透明度变化的backGroundImage,第二个是动态改变titleView的alpha
二、实现思路及主要代码:
1.要想实现页面中的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个tableView
let 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的层级,根据它的UI交互方式,作为subTableView的子视图的方式非常难以处理,这里是放在控制器主视图的最外层。这样subTableView水平滚动时它可以不会受影响;subTableView上下滚动的时候使用代理动态的调整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) // 因为有个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方法进行判断,如果headerView的子视图需要进行UI交互,就让该视图接收手势;否则就返回nil,也即是将手势方法传递到headerView下面的tableView上,这样headerView不点击子视图只是上下滚动就和直接滚动tableView效果一样。代码:
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
//需要交互的元素,点击时触发点击响应
for view in interactionItems {
if view.frame.contains(point){
return view
}
}
//点击需要交互的元素以外的区域,不触发点击响应
return nil
}
网友评论