我的思路是用 UICollectionView ,定义 100 组(每组就是那三张图片),然后当向左滑动到头的时候或者向右滑动到头的时候,定位到中间 50 组数据的部分,但是这样会有一个切换效果:就是当你向左滑动,本来动画是向左滑动的动画,但是当向左滑动到头的时候,他会向右切换到中间的位置,同样的向右滑动也是这样的道理,导致有明显的切换效果,大家有什么解决方案吗
或者采用其他什么思路实现左右循环滚动丝滑的切换
要实现的效果图; http://cdn.tudoutiao.pro/2023-09-07%2011.23.28.gif
我的仓库地址: https://github.com/tudoutiaoya/ScrollPicture
下面是我的代码
import UIKit
class HorizontalRollViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{
let collectionView: UICollectionView
let images = ["image1", "image2", "image3"]
let layout: UICollectionViewFlowLayout
var myOffsetX = 0.0 // 记录上次的 offsetx 便于判断是左滑还是右滑
let groupNum = 100 // 定义多少个组
let lineSpacing = 30.0
let itemWidth = UIScreen.main.bounds.width/2 // 卡片宽度
let itemHeigh = UIScreen.main.bounds.height/2
init() {
layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = self.lineSpacing
layout.itemSize = CGSize(width: itemWidth, height: itemHeigh)
layout.scrollDirection = .horizontal
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.decelerationRate = .fast
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
view.backgroundColor = .white
setupSubView()
// 初始定位到中间
collectionView.scrollToItem(at: IndexPath.init(item: groupNum/2 * images.count , section: 0), at: .centeredHorizontally, animated: false)
}
func setupSubView() {
collectionView.frame = view.bounds
collectionView.dataSource = self
collectionView.delegate = self
collectionView.isPagingEnabled = false
// 注册单元格
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "UICollectionViewCell")
view.addSubview(collectionView)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// 图片的数量
return groupNum * images.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "UICollectionViewCell", for:indexPath)
// 移除之前的子视图
cell.contentView.subviews.forEach { $0.removeFromSuperview() }
// 取余 计算出应该在 images 数组哪个位置
let imageIndex = indexPath.item % images.count
let imageView = UIImageView(image: UIImage(named: images[imageIndex]))
imageView.frame = cell.bounds
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
cell.contentView.addSubview(imageView)
return cell
}
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
// 停止滑动时,当前的偏移量(即最近停止的位置)
self.myOffsetX = scrollView.contentOffset.x
}
// collectionView.pagingEnabled = NO;
// 禁止分页滑动时,根据偏移量判断滑动到第几个 item
// 滑动 “减速滚动时” 是触发的代理,当用户用力滑动或者清扫时触发
func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
self.scrollToNextPageOrLastPage(scrollView)
}
// 用户拖拽时 调用
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
self.scrollToNextPageOrLastPage(scrollView)
}
func scrollToNextPageOrLastPage(_ scrollView: UIScrollView) {
// 到达左右边界,定位到中间
let contentWidth = (itemWidth+lineSpacing) * Double(groupNum*images.count) // 内容的总宽度
let adjustedContentWidth = contentWidth - lineSpacing // 调整后的内容宽度,减去最后一个间距
let rightOffset = adjustedContentWidth - scrollView.bounds.width // 右侧边界的偏移量
if (scrollView.contentOffset.x >= rightOffset || scrollView.contentOffset.x <= 0) {
collectionView.scrollToItem(at: IndexPath.init(item: groupNum/2 * images.count , section: 0), at: .centeredHorizontally, animated: false)
print("切换了")
return
}
// 之前停止的位置,判断左滑、右滑
if (scrollView.contentOffset.x > self.myOffsetX) { // 左滑,下一个( i 最大为 cell 个数)
// 计算移动的 item 的个数( item.width + 间距)
let i = Int(scrollView.contentOffset.x / (itemWidth + lineSpacing) + 1)
let indexPath = IndexPath(row: i, section: 0)
// item 居中显示
collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
} else { // 右滑,上一个( i 最小为 0 )
let i = Int(scrollView.contentOffset.x / (itemWidth + lineSpacing) + 1)
let indexPath = IndexPath(row: i, section: 0)
collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
}
}
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.