前言:9月份公司项目新增了类似简书个人中心样式的效果。同时要有支付宝的下拉刷新样式,自己思考了一下,做了一个简单的demo,借这次机会发表出来和大家一起学习一下
有需要的可以直接下载 Demo地址
废话不多说,先上效果图
从效果图看出需要思考的几个问题
1.上下滑动问题如何解决
2.下拉底部视图进行刷新更多(子视图)
3.子视图滑动需要考虑的问题
从这几个问题的角度出发,相信有思路之后问题很好解决的。
首先说一下我在写这个demo的过程中遇到的问题
1.父视图如何响应多个手势?
2.底部子控制器用什么控件比较好
3.最最关键的不能有冲突,
不卖关子了,说一下我写这个demo的思路供大家参考
1.从大的界面来说,最外层采用tableview,当然为了能同时响应多个手势,需要对这个父tableview进行处理
/**
考虑到底部tabview需要可以同时响应多个手势,所以自定义 TableView 以满足多个手势同时交互
*/
/**
同时识别多个手势
@param gestureRecognizer gestureRecognizer description
@param otherGestureRecognizer otherGestureRecognizer description
@return return value description
*/
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
2.父视图满足可以同时响应多个手势后,那么子视图因为考虑多有多个segmentControl,所以这里用户看到的底部滚动条上的三个视图,全部采用添加controller的方式,并且都继承于同一个父controller便于下边的滑动统一进行处理
考虑子动父不动,父动子不动,效果图可以看出,上划不超过headerView的高度的时候,是父视图的偏移量在滚动,而子视图不做偏移量变化,当超过headerView高度的时候继续向上滑动,此时的情况是父视图不进行偏移量变化,而子视图开始进行偏移量变化。并且效果图可以看出用户第一次进入界面的时候,是支持直接下拉刷新更多的。那么直接上关键代码
父视图和子视图分别声明一个变量用于管控滑动优先级。
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
if (scrollView == self.mainTableView) {
CGFloat tempContentOffsetY = scrollView.contentOffset.y;
CGFloat tabOffsetY = [self.mainTableView rectForSection:0].origin.y;
if (tempContentOffsetY<0) {// 偏移量小于0主视图不做偏移量变化,交给子视图进行处理
[[NSNotificationCenter defaultCenter] postNotificationName:@"showRefresh" object:nil];
[scrollView setContentOffset:CGPointZero];
}
_isTopIsCanNotMoveTabViewPre = _isTopIsCanNotMoveTabView;
if (tempContentOffsetY>=tabOffsetY) {// 当前滑动的偏移量大于等于headerView的时候,父视图不做偏移量变化,固定偏移量
scrollView.contentOffset = CGPointMake(0, tabOffsetY);
_isTopIsCanNotMoveTabView = YES;
}else {
_isTopIsCanNotMoveTabView = NO;
}
if (_isTopIsCanNotMoveTabView != _isTopIsCanNotMoveTabViewPre) {
if (!_isTopIsCanNotMoveTabViewPre && _isTopIsCanNotMoveTabView) {
//滑动到顶端
[[NSNotificationCenter defaultCenter] postNotificationName:@"goTop" object:nil userInfo:@{@"canScroll":@"1"}];
_canScroll = NO;
}
if(_isTopIsCanNotMoveTabViewPre && !_isTopIsCanNotMoveTabView){
// 离开顶部
if (!_canScroll) {
scrollView.contentOffset = CGPointMake(0, tabOffsetY);
}
}
}
}
}
子视图处理,这里通过通知来管控滑动的优先级
@interface NXHomePageClassViewController ()<UIGestureRecognizerDelegate>
{
BOOL is_span;// 为满足第一次进入界面直接下拉刷新准备
}
@end
@implementation NXHomePageClassViewController
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(acceptMsg:) name:@"goTop" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(acceptMsg:) name:@"leaveTop" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(normalRefresh:) name:@"showRefresh" object:nil];
is_span = YES;
}
- (void)normalRefresh:(NSNotification *)notification{
NSString *notificationName = notification.name;
if ([notificationName isEqualToString:@"showRefresh"]) {
is_span = YES;
self.scrollView.showsVerticalScrollIndicator = NO;
// 底部滚动视图接受showRefresh通知
}
}
-(void)acceptMsg : (NSNotification *)notification{
NSString *notificationName = notification.name;
if ([notificationName isEqualToString:@"goTop"]) {
NSDictionary *userInfo = notification.userInfo;
NSString *canScroll = userInfo[@"canScroll"];
if ([canScroll isEqualToString:@"1"]) {
is_span = NO;
self.canScroll = YES;
self.scrollView.showsVerticalScrollIndicator = NO;
// 底部滚动视图接受goTop通知
}
}else if([notificationName isEqualToString:@"leaveTop"]){
is_span = NO;
self.scrollView.contentOffset = CGPointZero;
self.canScroll = NO;
self.scrollView.showsVerticalScrollIndicator = NO;
// 底部滚动视图接受leaveTop通知
}
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
if (!_canScroll) {//不允许底部视图滑动
if (scrollView.contentOffset.y>0) {
is_span = NO;
}
}
if (is_span) {// 保证第一次进入可以直接下啦刷新,以及后续的下啦刷新
[scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x, scrollView.contentOffset.y)];
return;
}
if (!self.canScroll) {
[scrollView setContentOffset:CGPointZero];
return;
}
CGFloat offsetY = scrollView.contentOffset.y;
if (offsetY<=0) {
[[NSNotificationCenter defaultCenter] postNotificationName:@"leaveTop" object:nil userInfo:@{@"canScroll":@"1"}];
// 底部滚动视图发起leaveTop通知
}
_scrollView = scrollView;
}