论坛类应用双Tableview翻页效果实现

作为一名篮球爱好者,经常使用虎扑体育,虎扑体育应用最核心的部分就是其论坛功能,无论哪个版块,论坛都是其核心,而其论坛部分的实现又别具一格,它以两个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

感谢分享

时间: 2024-12-13 05:59:19

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

transform3D实现翻页效果

---恢复内容开始--- 闲篇 最近升级了下百度音乐,唯一的感觉就是动画效果很炫丽.我不是个对产品很敏感的人,但是这段时间观察一些大厂的产品发现现在的APP越来越重视动画效果了.大家可能没有注意过,连支付宝的一个很边缘很边缘的小角落(“财富 ->芝麻信用分 ->信用猜猜”)动画也是很炫的.随着手机硬件的增强以及广大苦逼程序员的不懈努力与钻研,APP的会越来越强调交互性,物理效果(UIDynamic)和动画效果(CoreAnimation)会越来越受欢迎. 准备 好吧,闲话不说了,首先跟大家坦白

android开发教程:android手势翻页效果

听麦子学院android开发老师说要实现手势翻页效果,主要用到ViewFlipper和GestureDetector.  ViewFlipper变化当前显示内容,GestureDetector监听手势.  用于多页的展示非常酷.  现在我就给大家简单说明下,  首先创建工程:TestFlip,创建主Activity:TestFlip.  在res/layout/main.xml中添加flipper信息,如下:  Java代码   1. <?xml version="1.0" en

iOS开发日记45-类似淘宝商品详情查看翻页效果的实现

今天博主有一个类似淘宝商品详情查看翻页效果的实现的需求,遇到了一些困难点,在此和大家分享,希望能够共同进步. 1.使用第三方框架 我用到的第三方库EGORefreshTableHeaderView下拉刷新的效果还有就是PWLoadMoreTableFooterView上拉加载更多 主要的思路在于UISCrollView两页,一页展示商品概况,另一页展示商品更多详情 首先,第一页的view包含一个UITableView,这个tableView实现PWLoadMoreTableFooterView中

HTML5翻页效果文字特效怎么实现呢

HTML5翻页效果文字特效怎么实现呢,之前在网上看到一款比较有新意的HTML5文字特效,文字效果是当鼠标滑过是出现翻开折叠的效果,类似书本翻页.于是我兴致勃勃的点开源码看了一下,发现其实实现也挺简单的,主要利用了CSS3的transform属性,分别对X轴.Y轴.Z轴进行翻转,先看一下效果截图. 看效果图这些文字是不是很有立体的感觉,而这个立体的感觉并不是有投影和阴影来实现的,而是通过翻转. 接下来我们来看一下源码.首先是HTML代码,非常简单,列出我们需要渲染的文字: <div class=&qu

Android翻页效果原理实现之翻页的尝试

尊重原创转载请注明:From AigeStudio(http://blog.csdn.net/aigestudio)Power by Aige 侵权必究! 炮兵镇楼 在<自定义控件其实很简单>系列的前半部分中我们用了整整六节近两万字两百多张配图讲了Android图形的绘制,虽然篇幅很巨大但仍然只是图形绘制的冰山一角,旨在领大家入门,至于修行成果就看各位的了--那么这个些列主要是通过前面学习到的一些方法来尝试完成一个翻页的效果. 对于我个人来说,我是不太建议大家在没自己去尝试前看本文的,因为你看

HTML5 book响应式翻页效果

翻页,HTML5源码下载,HTML5响应式翻页效果,鼠标移到右上角会看到翻页效果,需要鼠标拖动后翻页,支持ie9+,html5浏览器. 单页和双页. 自动播放和暂停. 点击左右翻页. 鼠标点击左右页面区域翻页. 鼠标点击左右页面区域拖拉翻页. ... 运行环境:HTML/PHP/ASP/ASP.NET/JSP... 相关标签:翻页 软件大小:953K 软件属性:共享版 | 简体中文 软件评级: 收录更新:2013-09-02 | 2013-09-02 相关链接:暂无演示 软件介绍: 摘要:HTM

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

之前在网上看到一款比较有新意的HTML5文字特效,文字效果是当鼠标滑过是出现翻开折叠的效果,类似书本翻页.于是我兴致勃勃的点开源码看了一下,发现其实实现也挺简单的,主要利用了CSS3的transform属性,分别对X轴.Y轴.Z轴进行翻转,先看一下效果截图. 看效果图这些文字是不是很有立体的感觉,而这个立体的感觉并不是有投影和阴影来实现的,而是通过翻转.        DEMO演示效果 接下来我们来看一下源码.首先是HTML代码,非常简单,列出我们需要渲染的文字: <div class="

c#翻页效果

用c#和GDI+实现杂志翻页动画效果时间:2010-01-13 blog.csdn.net 周公 - 说明:以前本人参与个一个电子杂志项目,当时要求实现模拟现实生活中的杂志翻页动画效果,别人推荐了这篇文章,最后达到了我想要的效果,今天尝试把这篇文章翻译了一下.希望对英语水平不太好的同行有帮助.如果你的英语水平足够好,我推荐你阅读英文原文,网址是:http://www.codeproject.com/KB/GDI-plus/TurnThePage.aspx,同时希望大家原谅本人的翻译水平. 介绍

turn.js 图书翻页效果

今天用turn.js 做图书的翻页效果遇到问题: 图片路径总是出错 调了一天,总算调出来了 我用的thinkphp,其他的不知道是不是一样 两个地方要改动: 1.后台查出地址 注意的地方:1.地址要完全的 2.js要用json格式的数据 $more = M('File')->where(array('id'=>$id))->find(); $more1 = json_decode($more['more'],true); foreach($more1 as $k => $v){ /