iOS UIScrollView 3种分页方法,间隔实现
基础知识参考
http://tech.glowing.com/cn/practice-in-uiscrollview/
方案一 PageEnable
http://www.cnblogs.com/JimmyBright/p/4324042.html
http://www.jianshu.com/p/9c1be359fd1b
关键点是:ScrollView PageEnable 翻页大小是ScrollView的bounds来的大小,在这个基础上需要一些 hacking 实现 bleeding 和 padding(即页与页之间有 padding,在当前页可以看到前后页的部分内容)

以下代码基于swift3,新建项目,替换ViewController内容即可运行,预览效果
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
private var contentScroll: UIScrollView!
private let scrollHeight: CGFloat = 400
private let appWidth: CGFloat = UIScreen.main.bounds.width
private let appHeight: CGFloat = UIScreen.main.bounds.height
private let padding: CGFloat = 10
private let totalCount: Int = 9
private var selectedIndex: Int = 0
// 设置ScrollView frame 起始点和终点左边位于超出屏幕的左右两侧,
// 从屏幕边缘到超出屏幕的终点之间的空隙,便是每两个view之间的间隔
// PageEnable 按ScrollView 的frame宽度进行翻页,每次滚动frame的宽度,
// add view 时,展示内容区域要设置在屏幕范围之内,空隙则有屏幕外的间隔形成
// 既有一下关系:
// 1. ScrollView.frame.width = 左侧间隙 + 屏幕的宽度 + 右侧间隙
// 2. 首页的frame.origin.x 在左侧屏幕外面,是负值,保证首个元素和屏幕对齐
// 3. 除第一个元素外,其余元素的左侧frame.origin.x 和前一个元素右侧终点x坐标重合,保证只有一个间隙,
// 由于间隙是重合的,所以元素view宽度打满屏幕还好,如果不是打满屏幕的话点击事件处理是个麻烦事情
override func viewDidLoad() {
super.viewDidLoad()
self.contentScroll = UIScrollView()
self.contentScroll.delegate = self
// 间隙的颜色
self.contentScroll.backgroundColor = UIColor.lightGray
self.contentScroll.isPagingEnabled = true
// 计算总的view的宽度
let totalFrameSize = (appWidth + (2*padding)) * CGFloat(totalCount)
self.contentScroll.contentSize = CGSize(width: totalFrameSize, height: 0)
self.contentScroll.frame = CGRect(x: -padding, y: (appHeight-scrollHeight)*0.5, width: appWidth + 2*padding, height: scrollHeight)
self.view.addSubview(self.contentScroll)
for index in 0...(totalCount - 1) {
let btn = UIButton()
btn.setTitle(String(index), for: .normal)
btn.backgroundColor = UIColor.brown
// 获取scroll view 的大小
let bounds = self.contentScroll.bounds
// 设定展示内容的view的frame宽度为:屏幕宽度
var pageFrame: CGRect = bounds
pageFrame.size.width = pageFrame.size.width - (2*padding)
// 设定展示内容的view的frame的origin位置在屏幕x坐标系的左侧起始点
pageFrame.origin.x = (bounds.size.width*CGFloat(index)) + padding
btn.frame = pageFrame
self.contentScroll.addSubview(btn)
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
}
}
方案二 snap
这种方法就是在 didEndDragging 且无减速动画,或在减速动画完成时,snap 到一个整数页。核心算法是通过当前 contentOffset 计算最近的整数页及其对应的 contentOffset,通过动画 snap 到该页。这个方法实现的效果都有个通病,就是最后的 snap 会在 decelerate 结束以后才发生,总感觉很突兀。
方案三 修改 targetContentOffset
oc:
- (CGPoint)nearestTargetOffsetForOffset:(CGPoint)offset
{
CGFloat pageSize = BUBBLE_DIAMETER + BUBBLE_PADDING;
NSInteger page = roundf(offset.x / pageSize);
CGFloat targetX = pageSize * page;
return CGPointMake(targetX, offset.y);
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
CGPoint targetOffset = [self nearestTargetOffsetForOffset:*targetContentOffset];
targetContentOffset->x = targetOffset.x;
targetContentOffset->y = targetOffset.y;
}
swift3
public func scrollViewWillEndDragging(_ scrollView: UIScrollView ,withVelocity velocity: CGPoint, targetContentOffset:
UnsafeMutablePointer<CGPoint>){
let pageWidth = Float(appWidth + itemSpacing)
let targetXContentOffset = Float(targetContentOffset.pointee.x)
var newPage = Float(currentPageIndex)
// I use this way calculate newPage:
newPage = roundf(targetXContentOffset / pageWidth);
// 以下方式在最后一页,左滑到最后一页时,左滑出现边角,然后在往右侧滑动,页面会直接跳动到倒数第二页,
// 是由于在这里使用velocity.x判断向左右翻页并不科学
//if velocity.x == 0 {
//newPage = floor( (targetXContentOffset - Float(pageWidth) / 2) / Float(pageWidth))
// + 1.0
//} else {
// newPage = Float(velocity.x > 0 ? newPage + 1 : newPage - 1)
// if newPage < 0 {
// newPage = 0
// }
// if (newPage > contentWidth / pageWidth) {
// newPage = ceil(contentWidth / pageWidth) - 1.0
// }
//}
// 滑动距离太短时,没有动画效果,解决方法:
targetContentOffset.pointee = CGPoint(x:scrollView.contentOffset.x, y: scrollView.contentOffset.y)
let pageWidth = Float(appWidth + itemSpacing)
let targetXContentOffset = Float(targetContentOffset.pointee.x)
// let contentWidth = Float(collectionView!.contentSize.width)
var newPage = Float(currentPageIndex)
newPage = roundf(targetXContentOffset / pageWidth);
let targetOffsetX = CGFloat(newPage * pageWidth)
let newPosition = CGPoint (x: targetOffsetX, y: targetContentOffset.pointee.y)
// 动画间隔一下避免冲突
DispatchUtils.dispatchAfterGap {
scrollView.setContentOffset(newPosition, animated: true)
}
}
滑动距离太短时,没有动画效果
-
collectionView.decelerationRate = UIScrollViewDecelerationRateFast
iOS UIScrollView 3种分页方法,间隔实现的更多相关文章
- phalcon几种分页方法
phalcon几种分页方法 一: use Phalcon\Paginator\Adapter\Model as PaginatorModel; // Current page to show // I ...
- PostgreSQL两种分页方法查询时间比较
数据库中存了3000W条数据,两种分页查询测试时间 第一种 SELECT * FROM test_table WHERE i_id> limit 100; Time: 0.016s 第二种 SE ...
- java oracle的2种分页方法
java oracle的2种分页方法 一物理分页: <!-- 分页查询所有的博客信息 --> <select id="findBlogs" resultType= ...
- sql server两种分页方法
方法一: --分页方法一 OrderID,CustomerID, EmployeeID,OrderDate,ShippedDate,ShipName,ShipAddress,Freight from ...
- iOS中 三种随机数方法详解
ios 有如下三种随机数方法: //第一种 srand((unsigned)time(0)); //不加这句每次产生的随机数不变 int i = rand() % 5; //第二种 srandom(t ...
- MVC三种分页方法
View部分: @using WebApplication1.Models;分页方法1引包 @*@using PagedList.Mvc; @using WebApplication1.Models; ...
- 数据分页 THINKPHP3.2 分页 三种分页方法
数据分页 复制本页链接 opensns 通常在数据查询后都会对数据集进行分页操作,ThinkPHP也提供了分页类来对数据分页提供支持. 下面是数据分页的两种示例. 第一种:利用Page类和limit方 ...
- Sql三种分页方法
--分页三种方法--第一种 ROW_NUMBER() OVER( ORDER BY OrgID) AS indexs 大于pagesize*pageindex,少于等于pagesize*(pagein ...
- sqlalchemy和flask-sqlalchemy的几种分页方法
sqlalchemy中使用query查询,而flask-sqlalchemy中使用basequery查询,他们是子类与父类的关系 假设 page_index=1,page_size=10:所有分页查询 ...
随机推荐
- zabbix服务端安装指南及常见问题解决
1. 首先要准备LNMP环境 2. 在mysql中创建zabbix所需要的库和用户 mysql -uroot -pmysql> CREATE DATABASE zabbix CHARACTER ...
- 2014-07-08 hibernate tenancy
http://en.wikipedia.org/wiki/Multitenancy http://www.infoq.com/news/2012/01/hibernate-4-released htt ...
- svg文字与图像
摘要: svg与canvas一样都可以将文本和图像放在画布中,制作出不一样的效果.下面是如何使用svg来渲染文本与图像. 简介: SVG的强大能力之一是它可以将文本控制到标准HTML页面不可能有的程度 ...
- highcharts图表中级入门:非histock图表的highcharts图表如何让图表产生滚动条
最近highcharts图表讨论群里面很多朋友都在问如何让highcharts图表在X轴数据多的情况下产生滚动条的问题,其实之前有一个解决办法是将装载图表的div容器用css样式表弄一个滚动条出来.这 ...
- VMWare------安装时出现无法将值写入注册表项
安装时提示详情: 无法打开注册表项UNKNOWN\Components\...请确认你是否有足够的权限访问该注册表项,或者与技术支持人员联系. 解决方法: 关掉360安全卫士等软件再安装
- Git Step by Step – (7) Git远程仓库(续)
上一篇文章介绍了Git远程仓库的一些使用,但是还是有些东西需要补充一下,所以有了这个续篇. .gitignore 前一篇中,我们介绍了Git的patch功能,当我们生成patch之后,"gi ...
- tomcat运行模式APR安装
centos6.2下,Tomcat运行模式apr安装过程,如下: 一.安装apr [root@vmT227-m5 /]# cd /usr/local/ [root@vmT227-m5 local]# ...
- 【easyswoole】 解决安装报错
在使用swoole 创建项目时候,报错 创建命令 composer create-project easyswoole/app easyswoole 错误信息: 解决办法,切换composer 源 镜 ...
- Esper学习之二:事件类型
Esper对事件有特殊的数据结构约定.能处理的事件结构有:POJO,java.util.Map,Object Array,XML 1.POJO 对于POJO,Esper要求对每一个私有属性要有gett ...
- css案例 - mask遮罩层的华丽写法
mask遮罩蒙层使用通常的写法的bug 通常写法pug .mask 通常写法css .mask{ position: absolute; top: 0; right: 0; bottom: 0; le ...