前言
实现UICollectionView的自动滚动,以及一屏下,中间显示一个view,两边显示半个view的效果,
如图:
自动滚动实现逻辑
自动滚动是使用Timer实现,每个一段时间让UICollectionView自动滚动下即可。
- 定义一个Timer
//自动滚动计时器
var autoScrollTimer:Timer?
- 定义一个下标,记录UICollectionView的下标
var index: Int = 0
- 启动一个定时器
func startTimer() {
//设置一个定时器,每三秒钟滚动一次
autoScrollTimer = Timer.scheduledTimer(timeInterval: 3, target: self,
selector: #selector(UICollectionViewTypeOneController.scroll),
userInfo: nil, repeats: true)
}
定时器没3秒响应scroll方法一次
- 自动滚动
//计时器时间一到,滚动一张图片
@objc func scroll(){
index = index + 1
index = index >= dataCollection.count ? 0 : index
collectionView.scrollToItem(at: IndexPath.init(row: index, section: 0), at: .centeredHorizontally, animated: true)
}
index 是下标,所以当index和数据源的大小一致时,就把index重置为0,否则就加一,scrollToItem方法是UICollectionView的自带方法,实现滚动效果。
一屏显示三个View
核心思想是实现UICollectionViewFlowLayout的prepare()和targetContentOffset方法
- 创建一个类实现UICollectionViewFlowLayout
class ProductAHorCollectionViewFlowLayout: UICollectionViewFlowLayout {
override func prepare() {
super.prepare()
}
override func targetContentOffset(forProposedContentOffset
proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
}
}
- prepare方法
prepare方法我们做一些初始化操作,如设置Item的大小和左右边距等
let left = (self.collectionView!.bounds.width - itemWidth) / 2
let top = (self.collectionView!.bounds.height - itemHeight) / 2
self.sectionInset = UIEdgeInsetsMake(top, left, top, left)
left 保证第一个和最后一个ItemView会居中显示
top 保证只显示一行。
至此我们已经实现了一个view居中显示,两边显示个头的效果,但是因为我们要保证,用户滑动结束后,中间的view一直显示在中间,所以要实现下targetContentOffset方法。
- targetContentOffset方法
override func targetContentOffset(forProposedContentOffset
proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
//停止滚动时的可见区域
let lastRect = CGRect(x: proposedContentOffset.x, y: proposedContentOffset.y,
width: self.collectionView!.bounds.width,
height: self.collectionView!.bounds.height)
//当前屏幕中点,相对于collect view上的x坐标
let centerX = proposedContentOffset.x + self.collectionView!.bounds.width * 0.5;
//这个可见区域内所有的单元格属性
let array = self.layoutAttributesForElements(in: lastRect)
//需要移动的距离
var adjustOffsetX = CGFloat(MAXFLOAT);
for attri in array! {
//每个单元格里中点的偏移量
let deviation = attri.center.x - centerX
//保存偏移最小的那个
if abs(deviation) < abs(adjustOffsetX) {
adjustOffsetX = deviation
}
}
//通过偏移量返回最终停留的位置
return CGPoint(x: proposedContentOffset.x + adjustOffsetX, y: proposedContentOffset.y)
}
原理就是计算出每一个view 的偏移量,获得最小偏移量的那个,原本停留的的位置 + 最小偏移量,就是一个view的居中位置。