Доброго времени суток товарищи))
Пытаюсь сделать бесконечный скроллинг на scrollView в обе стороны, использовать collectionView вот вообще намерений нет, да он тут и не поможет, скорее всего
В общем, скроллинг горизонтальный, на нем располагается 3 view, ширина каждой из которых равна ширине scrollView, так наглядней:
lazy var views = (0…2).map { UIView(frame: .init(
origin: .init(x: (scrollView.bounds.width) * CGFloat($0), y: 0),
size: .init(width: scrollView.bounds.width, height: scrollView.bounds.height))) }
эти view переиспользуются, т.е. у той что точно не появится и невинна сейчас меняется x координата
Для себя вижу два способа, это менять положение прямо внутри didScroll, после того как перешли за половину, у меня это получилось примерно так
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let xOffset = scrollView.contentOffset.x
let direction: ScrollDirection = lastOffsetX > xOffset ? .left : .right
lastOffsetX = xOffset
let page = Int(xOffset / scrollView.bounds.width)
let isHalf: Bool = {
switch direction {
case .left: return abs(scrollView.bounds.width * CGFloat(page) - xOffset) < scrollView.bounds.width / 2
case .right: return xOffset - scrollView.bounds.width * CGFloat(page) > scrollView.bounds.width / 2
}
}()
guard isHalf && page != latestPage || direction != latestDirection else { return }
self.latestPage = page
self.latestDirection = direction
let nextPage = (page + 2) % 3
let view = views[nextPage]
view.frame.origin.x = scrollView.bounds.width * CGFloat(page + (direction == .left ? -1 : 2))
}
Либо менять положение при окончании скроллинга
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
end(scrollView)
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
end(scrollView)
}
func end(_ scrollView: UIScrollView) {
let page = Int(scrollView.contentOffset.x / scrollView.frame.width)
guard
// page != latestPage,
let currentIndex = views.firstIndex(where: { $0.frame.origin.x == scrollView.contentOffset.x })
else { return }
latestPage = page
let nextIndex = (currentIndex + 1) % views.count
let previousIndex = (currentIndex + 2) % views.count
let currentView = views[currentIndex]
let nextView = views[nextIndex]
let previousView = views[previousIndex]
let width = scrollView.frame.width
currentView.frame.origin = .init(x: width, y: 0)
switch latestDirection {
case .left:
previousView.frame.origin = .init(x: width * 2, y: 0)
nextView.frame.origin = .zero
case .right:
nextView.frame.origin = .init(x: width * 2, y: 0)
previousView.frame.origin = .zero
}
scrollView.contentOffset = .init(x: width, y: 0)
}
в первом варианте не очень понимаю как можно подменять contentOffset так, чтобы все красиво встало на свои места, это актуально для обратного скроллинга
Во втором варианте, при быстром скроллинге не можно словить ситуацию, когда когда анимация не закончилась и тогда, при дальнейшем проскролливание вперед все встает, надеюсь понятно определил проблему)
Если кто-то делал что-то похожее и может подсказать, поделиться, послать(только в нужном русле, без ругательств) в нужное место, буду очень признателен
И для второго метода необходимо использовать paging, отличии от первого