论坛类应用双Tableview翻页效果实现
作为一名篮球爱好者,经常使用虎扑体育,虎扑体育应用最核心的部分就是其论坛功能,无论哪个版块,论坛都是其核心,而其论坛部分的实现又别具一格,它以两个tableview的形式翻页滚动显示,而不是常见的那种下拉加载更多,给用户以阅读软件般的翻页感受,用户体验相当完美!
分析
为了不改变tableview本身的特性,滚动,惯性等等,我们尝试重写tableview本身的panGesture手势,给它添加一个新的方法来实现tableview翻页时的移动。
panGesture本身的回调方法的执行是有误差的,那么我们必须在panGesture的方法对关键点进行约束。
实现
现在实现的效果如下:
123.gif
找到tableview开始发生位移的关键点,当tableview的偏移量大于0并且小于最大偏移量时说明tableview在正常滚动,不做操作,只记录下手势移动的translation以在后面手动推回时判断是否推到了起点
panGesture的translation是有误差,所以可能导致结果有偏差我们必须找到这些关键点加以限制以免误差的出现
翻页后要调整好两个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&¤tTable.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翻页效果实现的更多相关文章
- transform3D实现翻页效果
---恢复内容开始--- 闲篇 最近升级了下百度音乐,唯一的感觉就是动画效果很炫丽.我不是个对产品很敏感的人,但是这段时间观察一些大厂的产品发现现在的APP越来越重视动画效果了.大家可能没有注意过,连 ...
- Android 实现书籍翻页效果----完结篇
By 何明桂(http://blog.csdn.net/hmg25) 转载请注明出处 之前由于种种琐事,暂停了这个翻页效果的实现,终于在这周末完成了大部分功能,但是这里只是给出了一个基本的雏形,没有添 ...
- Android 实现书籍翻页效果----升级篇
自从之前发布了<Android 实现书籍翻页效果----完结篇 >之后,收到了很多朋友给我留言,前段时间由于事情较多,博客写得太匆忙很多细节地方没有描述清楚.所以不少人对其中的地方有不少不 ...
- HTML5 book响应式翻页效果
翻页,HTML5源码下载,HTML5响应式翻页效果,鼠标移到右上角会看到翻页效果,需要鼠标拖动后翻页,支持ie9+,html5浏览器. 单页和双页. 自动播放和暂停. 点击左右翻页. 鼠标点击左右页面 ...
- 简单做出HTML5翻页效果文字特效
之前在网上看到一款比较有新意的HTML5文字特效,文字效果是当鼠标滑过是出现翻开折叠的效果,类似书本翻页.于是我兴致勃勃的点开源码看了一下,发现其实实现也挺简单的,主要利用了CSS3的transfor ...
- c#翻页效果
用c#和GDI+实现杂志翻页动画效果时间:2010-01-13 blog.csdn.net 周公 - 说明:以前本人参与个一个电子杂志项目,当时要求实现模拟现实生活中的杂志翻页动画效果,别人推荐了这篇 ...
- webapp应用--模拟电子书翻页效果
前言: 现在移动互联网发展火热,手机上网的用户越来越多,甚至大有超过pc访问的趋势.所以,用web程序做出仿原生效果的移动应用,也变得越来越流行了.这种程序也就是我们常说的单页应用程序,它也有一个英文 ...
- 采用cocos2d-x lua 的listview 实现pageview的翻页效果之上下翻页效果
--翻页滚动效果local function fnScrollViewScrolling( sender,eventType) -- body if eventType == 10 the ...
- css实现翻页效果
如图,鼠标移动到图上,实现右上角翻页的效果,本例主要border边框的设置. 一.基本概念 <html> <head> <style> #demo{ width:0 ...
随机推荐
- Google Map Api 谷歌地图接口整理
一:基本知识: 1. 使用谷歌地图 API 的第一步就是要注册一个 API 密钥,需要注重一下两点: 1.假如使用 API 的页面还没有发布,只是在本地调试,可以不用密钥,随便用个字符串代替就可以了. ...
- ASP.NET缓存全解析3:页面局部缓存 转自网络原文作者李天平
有时缓存整个页面是不现实的,因为页的某些部分可能在每次请求时都需要变化.在这些情况下,只能缓存页的一部分.顾名思义,页面部分缓存是将页面部分内容保存在内存中以便响应用户请求,而页面其他部分内容则为动态 ...
- 每天一道LeetCode--409 .Longest Palindrome
Given a string which consists of lowercase or uppercase letters, find the length of the longest pali ...
- SQL语句新建表,同时添加主键、索引、约束
SQL语句新建数据表 主键,索引,约束 CREATE TABLE [dbo].[T_SendInsideMessageRec]( [SendInsideMID] [uniqueidentifier ...
- java中从1000万个随机数中查找出相同的10万个随机数花的最少时间
偶然在群里看到有人问到大数据查询,自己也就想了小艾改如何解决,从从1000万个随机数中查找出相同的10万个随机数花的最少时间, 谈到效率,自然是hashmap莫属. import java.util. ...
- (转)MongoDB 实现currentOp定时捕获
问题描述: 当分析生产环境发生的性能问题时,常常因为没有实时的依据而无从下手.那么笔者通过捕获db.currentOp()到文件,并作为定时任务,可供后续分析. 解决方法: 步骤一:Shell脚本记录 ...
- (转)MongoDB分片实战 集群搭建
环境准备 Linux环境 主机 OS 备注 192.168.32.13 CentOS6.3 64位 普通PC 192.168.71.43 CentOS6.2 64位 服务器,NUMA CPU架构 Mo ...
- 30类css选择器
大概大家都知道id,class以及descendant选择器,并且整体都在使用它们,那么你正在错误拥有更大级别的灵活性的选择方式.这篇文章里面提到的大部分选择器都是在CSS3标准下的,所以它们只能在相 ...
- Microsoft.Xna.Framework.TitleContainer.OpenStream()
/// <summary> /// This method opens a file using System.IO classes and the /// TitleLocation p ...
- 防止双击选中html中文字
在开发过程中很常用的会给<span></span>等内联元素增加一个onlick事件,但是经常发生的一件事情就是点击的时候,选中了span中的字体:倒是不影响主逻辑,但是很难受 ...