设为首页 加入收藏

TOP

UIScrollView 和 UICollectionView 分页效果(二)
2017-10-12 12:02:04 】 浏览:10131
Tags:UIScrollView UICollectionView 效果
外会响应触摸的区域(用bounds最初的坐标)写成数组进行赋值。例如,frame(30, 0, 100, 100),要让左边宽 30、高 100 的区域为响应区域,则给interactionAreaNotInBounds赋值为[CGRect(x: -30, y: 0, width: 30, height: 100)]

当要分页的页数较少、每页内容不多的时候,可以用这个方法实现。如果要显示很多页的内容,一次把所有分页视图加到 scroll view 上,影响性能。这种情况可以用UICollectionView实现,UICollectionViewCell是重用的,节约资源。用UICollectionView实现的方法不同。

UICollectionView 分页

如果UICollectionView用以上的方法实现,出现的问题是,不在bounds之内的UICollectionViewCell可能消失。因为 cell 是重用的,移出bounds之后可能就被移除而准备重用。UICollectionView继承自UIScrollView,可以通过UIScrollViewDelegate的方法,模拟分页效果。具体实现方法与分页大小有关。

分页较大

当分页较大时,比如水平滚动,一页宽度大于屏幕宽度一半,每次滚动的最远距离就限制到相邻分页。这样的限制与isPagingEnabled的效果基本符合。实现UIScrollViewDelegate的一个方法即可。

private var selectedIndex: Int = 0 // index of page displayed
private let cellWidth: CGFloat = UIScreen.main.bounds.width - 100
private let cellHeight: CGFloat = 100

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    // Destination x
    let x = targetContentOffset.pointee.x
    // Page width equals to cell width
    let pageWidth = cellWidth
    // Check which way to move
    let movedX = x - pageWidth * CGFloat(selectedIndex)
    if movedX < -pageWidth * 0.5 {
        // Move left
        selectedIndex -= 1
    } else if movedX > pageWidth * 0.5 {
        // Move right
        selectedIndex += 1
    }
    if abs(velocity.x) >= 2 {
        targetContentOffset.pointee.x = pageWidth * CGFloat(selectedIndex)
    } else {
        // If velocity is too slow, stop and move with default velocity
        targetContentOffset.pointee.x = scrollView.contentOffset.x
        scrollView.setContentOffset(CGPoint(x: pageWidth * CGFloat(selectedIndex), y: scrollView.contentOffset.y), animated: true)
    }
}

selectedIndex表示当前分页序号,默认显示最左边的一页,因此初始化为 0。如果最开始显示其他页,需要改变selectedIndex的值。通过selectedIndex的值,将要停下来的坐标x,计算出位移movedX。当位移绝对值大于分页宽度的一半时,滚动到位移方向的相邻页。

targetContentOffset.pointee.x赋值,改变滚动终点的x坐标。宽度较大的分页效果滚动速率不能太慢,所以当速率小于 2 时,给targetContentOffset.pointee.x赋值为当前位置即停止滚动,调用setContentOffset(_ contentOffset: CGPoint, animated: Bool)方法,立即以默认速度滚动到终点。

现在,还有一个小问题,就是滚动到最后一页时,滚动停止的位置不固定。最后一页停止的位置有时候靠屏幕左边,有时靠右。从最后一页往回滚动可能会有点奇怪(突然加速)。解决办法是增加一个UICollectionViewCell放到最后,cell 的宽度为屏幕宽度减分页宽度,使最后一页滚动的停止位置都靠屏幕左边。假设分页数量(UICollectionViewCell的数量)为numberOfItems,以下是 cell 的大小

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    switch indexPath.item {
    case numberOfItems:
        return CGSize(width: UIScreen.main.bounds.width - cellWidth, height: cellHeight)
    default:
        return CGSize(width: cellWidth, height: cellHeight)
    }
}

分页较小

当分页较小时,屏幕宽度可以显示好几个分页,就不能把滚动距离限制到相邻分页。直接判断滚动终点离哪个分页比较近,以近的分页为终点。

private let cellWidth: CGFloat = 100
private let cellHeight: CGFloat = 100

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    // Destination x
    let x = targetContentOffset.pointee.x
    // Page width equals to cell width
    let pageWidth = cellWidth
    // Destination page index
    var index = Int(x / pageWidth)
    // Check whether to move to next page
    let divideX = CGFloat(index) * pageWidth + pageWidth * 0.5
    if x > divideX {
        // Should move to next page
        index += 1
    }
    // Move to destination
    targetContentOffset.pointee.x = pageWidth * CGFl
首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇OtherViews系统控件 下一篇Swift应用案例 1.无限轮播

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目