作为一名篮球爱好者,经常使用虎扑体育,虎扑体育应用最核心的部分就是其论坛功能,无论哪个版块,论坛都是其核心,而其论坛部分的实现又别具一格,它以两个tableview的形式翻页滚动显示,而不是常见的那种下拉加载更多,给用户以阅读软件般的翻页感受,用户体验相当完美!

分析

  1. 为了不改变tableview本身的特性,滚动,惯性等等,我们尝试重写tableview本身的panGesture手势,给它添加一个新的方法来实现tableview翻页时的移动。

  2. panGesture本身的回调方法的执行是有误差的,那么我们必须在panGesture的方法对关键点进行约束。

实现

现在实现的效果如下:

123.gif

  1. 找到tableview开始发生位移的关键点,当tableview的偏移量大于0并且小于最大偏移量时说明tableview在正常滚动,不做操作,只记录下手势移动的translation以在后面手动推回时判断是否推到了起点

  2. panGesture的translation是有误差,所以可能导致结果有偏差我们必须找到这些关键点加以限制以免误差的出现

  3. 翻页后要调整好两个tableview和BackView之间的层级顺序

主要结构,两个tableview,和一个上面有Label的backView,都用懒加载实例化,给tableview的panGesture添加一个方法。
同时需要几个变量如下:

枚举类型来判断滑动方向:

typedef NS_ENUM(NSUInteger, TurnPageDirection) {
   TurnPageDirectionUp,
   TurnPageDirectionDown,
};

用currentTable和lastTable分别表示当前操作的tableview和前一次操作的tableview,pageIndex记录页数,lastDistace记录在开始翻页前手势移动的距离;SH,SW分别是指屏幕高度和宽度

    UITableView currentTable,lastTable;
   int pageIndex;
   CGPoint lastDistance;
   TurnPageDirection turnDirection;

懒加载两个tableview,个它们的panGesture加一个自定义的方法。

- (UITableView )oddTable{
   if (!_oddTable) {
       _oddTable = [[UITableView alloc]initWithFrame:self.view.bounds];
       _oddTable.delegate=self;
       _oddTable.dataSource=self;
       [_oddTable.panGestureRecognizer addTarget:self action:@selector(pan:)];
   }
   return _oddTable;
}
- (UITableView )evenTable{
   if (!_evenTable) {
       _evenTable = [[UITableView alloc]initWithFrame:self.view.bounds];
       _evenTable.delegate=self;
       _evenTable.dataSource=self;
       [_evenTable.panGestureRecognizer addTarget:self action:@selector(pan:)];
   }
   return _evenTable;
}

核心部分

下面是几个必须遵守的约束条件:

-(void)pan:(UIPanGestureRecognizer *)sender{
//如果在下拉的过程中,去滚动了lastTableview,则返回,以免影响当前的操作
   if (sender.view != currentTable) return;
   CGPoint moveDistance=[sender translationInView:self.view];
//在上拉手动推回速度过大时可能导致,translation变成正数而导致tableview的y变为负的,即下方有空出部分
   if (currentTable.frame.origin.y > 0) {
       [currentTable setFrame:self.view.bounds];
   }
//同样在下拉推回时也可能导致lastTable的y大于-SH,即并没有完全上去,上方有空出部分
   if (lastTable.frame.origin.y > 0) {
       [lastTable setFrame:self.view.bounds];
   }
//如果当前tableview.y为负,当前tableview必须一直保持最大偏移量
   if(currentTable.frame.origin.y < 0){
       [currentTable setContentOffset:CGPointMake(0, maxoffset)];
   }
//如果上一个tableview处于移动状态,当前tableview必须保持0偏移
   if ((lastTable.frame.origin.y < 0)&&(lastTable.frame.origin.y > -SH)) {
       [currentTable setContentOffset:CGPointZero];
   }

开始滚动:

1.正常滚动时,记录下正常滚动时手势的translation
2.假如正常滚动到底部后再开始拖动位移,那么必须将记录重置为零,因为此时再移动并不会触发1中的赋值操作,那么第一下移动会是跳动
   if(currentTable.contentOffset.y<maxoffset&&currentTable.contentOffset.y>0) {
       lastDistance=moveDistance;
       if (sender.state == UIGestureRecognizerStateEnded) {
           lastDistance = CGPointZero;
           moveDistance = CGPointZero;
       }
   }
开始翻页
   else{
手动推回,分为上拉时推回和下拉时推回,两者需要分开判定
   1.上拉时推回
       if (moveDistance.y-lastDistance.y >= 0&&turnDirection == TurnPageDirectionUp) {
           self.backView.alpha = 1;
           [currentTable setFrame:CGRectMake(0, 0, SW, SH)];
       }
   2.下拉时推回
       else if((moveDistance.y-lastDistance.y <=0)&&turnDirection == TurnPageDirectionDown){
           self.backView.alpha = 0;
           [lastTable setFrame:CGRectMake(0, -SH, SW, SH)];
       }
1.开始上拉翻页,首先,需要设置好lasttable和backView以及currentTable的层级
2.在手松开时根据currentTable的y判定是否翻页
       if (currentTable.contentOffset.y>=maxoffset&&moveDistance.y<0) {              [lastTable setFrame:self.view.bounds];             [self.view insertSubview:lastTable atIndex:self.view.subviews.count-3];             [self.view insertSubview:self.backView atIndex:self.view.subviews.count-2];             [lastTable setContentOffset:CGPointZero];             turnDirection = TurnPageDirectionUp;             [currentTable setContentOffset:CGPointMake(0, maxoffset)];             [self.backView.footerLabel setText:[NSString stringWithFormat:@"上翻至第%d页",pageIndex+1]];             [currentTable setFrame:CGRectMake(0,moveDistance.y-lastDistance.y, SW, SH)];             [self.backView setAlpha:(currentTable.frame.origin.y+SH)/SH];             if (sender.state==UIGestureRecognizerStateEnded) {                  lastDistance = CGPointZero;                 if (currentTable.frame.origin.y<-100) {                     [UIView animateWithDuration:0.5*(currentTable.frame.origin.y+SH)/SH animations:^{                         [currentTable setFrame:CGRectMake(0,-SH , SW, SH)];                     }completion:^(BOOL finished) {                          [self.backView setAlpha:(currentTable.frame.origin.y+SH)/SH];                         pageIndex++;                         lastTable=currentTable;                         currentTable=[self tableWithIndex:pageIndex];                         return ;                     }];                 }else{                     [UIView animateWithDuration:-(currentTable.frame.origin.y)/SH*0.5 animations:^{                         [self.backView setAlpha:(currentTable.frame.origin.y+SH)/SH];                         [currentTable setFrame:CGRectMake(0,0 , SW, SH)];                     }completion:^(BOOL finished) {                      }];                 }             }         }  1.开始下拉翻页,首先,需要设置好lasttable和backView以及currentTable的层级 2.如果是首页,则返回 3.在手松开时根据lastTable的y判定是否翻页         else if(currentTable.contentOffset.y <= 0&&moveDistance.y >= 0){
           [lastTable setFrame:CGRectMake(0, -SH, SW, SH)];
           [self.view insertSubview:lastTable atIndex:self.view.subviews.count-1];
           [self.view insertSubview:self.backView atIndex:self.view.subviews.count-2];
           if (pageIndex == 1)  return;
           turnDirection = TurnPageDirectionDown;
           [currentTable setContentOffset:CGPointMake(0, 0)];
           [lastTable setFrame:CGRectMake(0,moveDistance.y-SH-lastDistance.y, SW, SH)];
           [self.backView setAlpha:(lastTable.frame.origin.y+SH)/SH];
           [_backView.footerLabel setText:[NSString stringWithFormat:@"下翻至第%d页",pageIndex-1]];
           if (sender.state == UIGestureRecognizerStateEnded) {
               lastDistance = CGPointZero;
               if (lastTable.frame.origin.y > 100-SH) {
                   [UIView animateWithDuration:0.5(-lastTable.frame.origin.y)/SH animations:^{
                       [lastTable setFrame:CGRectMake(0,0, SW, SH)];
                   }completion:^(BOOL finished) {
                       [self.backView setAlpha:currentTable.frame.origin.y/SH];
                       pageIndex--;
                       lastTable = currentTable;
                       currentTable = [self tableWithIndex:pageIndex];
                       return ;
                   }];
               }else{
                   [UIView animateWithDuration:(SH+currentTable.frame.origin.y)/SH0.5 animations:^{
                       [self.backView setAlpha:currentTable.frame.origin.y/SH];
                       [lastTable setFrame:CGRectMake(0,-SH, SW, SH)];
                   }completion:^(BOOL finished) {
                       [lastTable setFrame:CGRectMake(0, 0, SW, SH)];
                       [self.view insertSubview:lastTable atIndex:self.view.subviews.count - 3];
                       return ;
                   }];
               }
           }
       }
   }
}

tableview根据页面变换方法

- (UITableView*)tableWithIndex:(int)index{
   if (index%2 == 0) {
       return self.evenTable;
   }
   return self.oddTable;
}

总结

第一次用markdown,第一次写博客写的很粗糙,个人觉得panGesture是个挺不好的方法,希望大家提供点更好的,不改变tableview本身特性,又能实现本文需要效果的方法,谢谢!然后代码写的不够优雅,要多看开源代码和大神的轮子!
github博客地址:https://joey520.github.io/
源码地址:https://github.com/joey520/HUPUTableView

原文链接:http://www.jianshu.com/p/bfc39ba5bb5c

感谢分享

论坛类应用双Tableview翻页效果实现的更多相关文章

  1. transform3D实现翻页效果

    ---恢复内容开始--- 闲篇 最近升级了下百度音乐,唯一的感觉就是动画效果很炫丽.我不是个对产品很敏感的人,但是这段时间观察一些大厂的产品发现现在的APP越来越重视动画效果了.大家可能没有注意过,连 ...

  2. Android 实现书籍翻页效果----完结篇

    By 何明桂(http://blog.csdn.net/hmg25) 转载请注明出处 之前由于种种琐事,暂停了这个翻页效果的实现,终于在这周末完成了大部分功能,但是这里只是给出了一个基本的雏形,没有添 ...

  3. Android 实现书籍翻页效果----升级篇

    自从之前发布了<Android 实现书籍翻页效果----完结篇 >之后,收到了很多朋友给我留言,前段时间由于事情较多,博客写得太匆忙很多细节地方没有描述清楚.所以不少人对其中的地方有不少不 ...

  4. HTML5 book响应式翻页效果

    翻页,HTML5源码下载,HTML5响应式翻页效果,鼠标移到右上角会看到翻页效果,需要鼠标拖动后翻页,支持ie9+,html5浏览器. 单页和双页. 自动播放和暂停. 点击左右翻页. 鼠标点击左右页面 ...

  5. 简单做出HTML5翻页效果文字特效

    之前在网上看到一款比较有新意的HTML5文字特效,文字效果是当鼠标滑过是出现翻开折叠的效果,类似书本翻页.于是我兴致勃勃的点开源码看了一下,发现其实实现也挺简单的,主要利用了CSS3的transfor ...

  6. c#翻页效果

    用c#和GDI+实现杂志翻页动画效果时间:2010-01-13 blog.csdn.net 周公 - 说明:以前本人参与个一个电子杂志项目,当时要求实现模拟现实生活中的杂志翻页动画效果,别人推荐了这篇 ...

  7. webapp应用--模拟电子书翻页效果

    前言: 现在移动互联网发展火热,手机上网的用户越来越多,甚至大有超过pc访问的趋势.所以,用web程序做出仿原生效果的移动应用,也变得越来越流行了.这种程序也就是我们常说的单页应用程序,它也有一个英文 ...

  8. 采用cocos2d-x lua 的listview 实现pageview的翻页效果之上下翻页效果

    --翻页滚动效果local function fnScrollViewScrolling( sender,eventType)    -- body    if eventType == 10 the ...

  9. css实现翻页效果

    如图,鼠标移动到图上,实现右上角翻页的效果,本例主要border边框的设置. 一.基本概念 <html> <head> <style> #demo{ width:0 ...

随机推荐

  1. android百度地图中的地图缩放级别

    前期搭建百度地图的环境就不说了,网上一搜一大把,这里只讲地图的缩放,大神可以直接绕道 首先在类的内部初始化一个百度地图的对象 private BaiduMap mBaiduMap; 然后在OnCrea ...

  2. 十大Intellij IDEA快捷键(转)(2015年06月15日)

    注:本文转自:http://blog.csdn.net/dc_726/article/details/42784275 Intellij IDEA中有很多快捷键让人爱不释手,stackoverflow ...

  3. @@Error使用简单小结

    使用中经常用到@@Error来判断上一个语句是否执行成功,对此小结一下,可能有些不准确,欢迎指出. 1.1  介绍 SQL SERVER 中@@表示系统全局变量 (1)   返回执行的上一个 Tran ...

  4. 每天一道LeetCode--409 .Longest Palindrome

    Given a string which consists of lowercase or uppercase letters, find the length of the longest pali ...

  5. Part 11 string functions in sql server

    Built in string functions in sql server 2008 LEFT, RIGHT, CHARINDEX and SUBSTRING functions in sql s ...

  6. win7开启远程桌面

    1.启用windows防火墙 计算机管理----->服务----->Windows Firewall(双击进入,启动类型改为自动,点击应用,点击启动)2.启动gpedit.msc打开“本地 ...

  7. 【原创】Tomcat集群环境下对session进行外部缓存的方法(1)

    BJJC网改版, 计划将应用部署在tomcat集群上,集群的部署方案为Apache+Tomcat6,连接件为mod_jk,其中开启了session复制和粘性session.计划节点数为3个. 到这,或 ...

  8. 理解C#系列 / 核心C# / 常量

    常量 常量? 我对常量的理解就是在初始化完成后再也不变的“全局变量”. 定义常量 [const][空格][变量类型][空格][变量名称][=][值][:] const表示定义的是常量. 常量特点 常量 ...

  9. 对象this、currentTarget和target

    在事件处理程序内部,对象this始终等于currentTarget的值,而target则只包含事件的实际目标.如果直接将事件处理程序指定给了目标元素,则this.currentTarget和targe ...

  10. /mnt /media /dev 目录区别

    /mnt 是被系统管理员使用,手动挂载一些临时媒体设备的目录. /medai 是自动挂载的目录,比如我们的U盘插在ubuntu下回自动挂载,就会在/media下生成一个目录,这个目录就是U盘所在目录, ...