正确处理iOS从下方滑出滚动视图
本文提供 Demo下载
在iOS 11开始,从最早的地图应用到最近的捷径,陆续有系统应用使用从下方滑出列表的形式,这种系统提供的圆角风格视图用手势划出和隐藏时非常自然流畅。国内的一些应用也跟进了这种交互方式,但是我发现很大一部分APP都没有正确的处理ScrollView滚动和视图滚动的衔接,以至于相比于系统应用不够自然。比如知乎、抖音的评论列表页,需要手指拿开一下才能切换视图移动和scroll滚动,衔接不够连续。
此文没什么技术含量,只提供了一种处理技巧正确处理类似这种嵌套滚动时响应对象的切换,让你的应用和系统应用一样自然流畅。我更多的目的是一种呐喊,希望国内这些常用app能够注意到这些使用细节。
(系统应用的滑出视图)
(Demo跑出来的效果,压缩了分辨率,保留原始帧率)
因为此场景下有2种滑动,一种是视图向上移动ScrollView不滚动,另一种模式是ScrollView滑动而视图不移动,我们可能很自然的想到另外添加一个手势,禁止ScrollView滚动,然后再去驱动视图向上移动,在不需要的时候再去禁止这个手势和开启ScrollView滚动。如果这么处理,可能就会发现永远也得不到一个衔接自然的滚动体验。
我的方法是不要禁止ScrollView的手势,但是可以取消ScrollView滚动:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
scrollView.contentOffset = CGPointMake(0, 0);
}
另外如果你理解了ScrollView的实现,那么就不用再另外添加手势了,因为本身ScrollView也是由手势驱动的,而我们可以直接得到scrollView.panGestureRecognizer:
[scrollView.panGestureRecognizer addTarget:self action:@selector(panGestureHandle:)];
大部分事物处理就将交给panGestureHandle处理了:
// 核心函数:手势处理
- (void)panGestureHandle:(UIPanGestureRecognizer *)tap {
static CGPoint startPoint;
static CGPoint viewPoint;
static BOOL isBegan;
CGPoint endPoint;
if ((self.tableView.contentOffset.y > 0 && self.sizeState == SlideScrollViewStateFull)
|| self.top < FULL_TOP) {
isBegan = NO;
[self panGestureEndWithViewPoint:viewPoint];
return;
}
_scrollDecelerat = NO;
self.tableView.showsVerticalScrollIndicator = NO;
if (tap.state == UIGestureRecognizerStateBegan || isBegan == NO) {
isBegan = YES;
startPoint = [tap locationInView:self.superview];
viewPoint = self.origin;
}
switch (tap.state) {
case UIGestureRecognizerStateChanged: {
endPoint = [tap locationInView:self.superview];
CGFloat toPointY = viewPoint.y + (endPoint.y - startPoint.y);
self.top = toPointY;
}
break;
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled:
case UIGestureRecognizerStateFailed: {
isBegan = NO;
[self panGestureEndWithViewPoint:viewPoint];
}
default:
break;
}
}
这里有需要注意的地方就是我们需要手动计算一次手势移动的距离,因为一个手势可能前一部分在响应ScrollView的滚动,而后一部分又切换到了移动视图,所以开始移动的点可能并不是手势开始的时候。
如果还有非ScrollView区域,这时候就可以另外添加一个手势到这个区域视图上了,如demo中的搜索框部分,处理函数和上面一样即可。
有更多细节比如使ScrollView取消惯性滚动等,可以马上查看Demo了解,这里就不一一列举了。
p.p1 { margin: 0; font: 11px Menlo; color: rgba(255, 255, 255, 1); background-color: rgba(40, 43, 53, 1) }
p.p2 { margin: 0; font: 11px Menlo; color: rgba(77, 191, 86, 1); background-color: rgba(40, 43, 53, 1) }
p.p3 { margin: 0; font: 11px Menlo; color: rgba(147, 201, 106, 1); background-color: rgba(40, 43, 53, 1) }
p.p4 { margin: 0; font: 11px Menlo; color: rgba(0, 175, 202, 1); background-color: rgba(40, 43, 53, 1) }
span.s1 { color: rgba(194, 52, 155, 1) }
span.s2 { color: rgba(0, 175, 202, 1) }
span.s3 { color: rgba(139, 132, 207, 1) }
span.s4 { color: rgba(147, 201, 106, 1) }
span.s5 { color: rgba(255, 255, 255, 1) }
p.p1 { margin: 0; font: 11px Menlo; color: rgba(255, 255, 255, 1); background-color: rgba(40, 43, 53, 1) }
最新文章
- 运用Mono.Cecil 反射读取.NET程序集元数据
- MVC5 + EF6 入门完整教程二:从前端的UI开始
- pbfunc外部函数扩展应用-在Powerbuilder中进行Http的GET、POST操作
- 【mysql】关于checkpoint机制
- java中length,length(),size()的区别
- leetcode First Missing Positive hashset简单应用
- 复杂事件处理引擎—Esper工作原理
- live555学习经验链接二
- 一段代码让你秒懂java方法究竟是传值还是传地址
- 在Apk应用程序内,查找某个Activity。
- How to parse project properties or how to parse files with key-value pair
- web安全与防御
- PyCharm 2017.3 下载与安装
- spring cloud 路由网关zuul基本使用
- webView 获取内容高度不准确的原因是因为你设置了某个属性
- idea 项目打包发布
- 实现与JS相同的Des加解密算法【转】
- CodeForces822A
- SaltStack salt-key 命令
- 【转】通过CountDownLatch提升请求处理速度