我的思路是用 UICollectionView ,定义 100 组(每组就是那三张图片),然后当向左滑动到头的时候或者向右滑动到头的时候,定位到中间 50 组数据的部分,但是这样会有一个切换效果:就是当你向左滑动,本来动画是向左滑动的动画,但是当向左滑动到头的时候,他会向右切换到中间的位置,同样的向右滑动也是这样的道理,导致有明显的切换效果,大家有什么解决方案吗
或者采用其他什么思路实现左右循环滚动丝滑的切换
下面是我的代码
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)
}
}
}
1
tsanie 2023-09-07 16:25:35 +08:00
这种需求用 UIPageViewController 是不是好点
|
2
kera0a 2023-09-07 16:26:38 +08:00 via iPhone
就三个 UIImageView 放到 UIScrollView 上,监听 scrollView 的滚动,到临界点了调整已经移出屏幕的 ImageView 坐标。
调整 frame 性能开销很小,你只要计算好了可以无限滚动循坏 另外这种效果 github 搜一下能搜到 1000 个,不用自己写 |
3
tizzy1 2023-09-07 16:29:25 +08:00
看看有没有分页效果,有分页效果就 UIScrollView+三张图片的思路,没有分页效果还要很丝滑,就 UICollectionView ,不过不用定义 100 组,itemCount 那个代理方法直接返回 10000 ,在 cellforRowAtIndexPath 方法里处理逻辑,反正 cell 都是复用的,绝对丝滑!!
|
4
chiaf 2023-09-07 16:31:18 +08:00
可以去看下官方的 swiftUI 教程,里面有使用 UIPageViewController 实现轮播图的 demo 😂。
但是 UIPageViewController 这个类据说有 bug |
5
tudoutiaoya OP |
6
tudoutiaoya OP @kera0a UIScrollView 能实现,一个屏幕中显示三张图片吗,中间图片完整的显示在中间,左右两边分别有上一张和下一张的图片,🤔,我试试
|
7
xaoflysho 2023-09-07 17:14:25 +08:00
翻了好久,终于找到了!当时按照这个视频写了一个可以无限滚动的 Dashboard
&list=PLmEZjI7vcqES-hEaDBXVFtyJ_5mUa0umr&index=1 视频里的代码在这里: https://github.com/gspiers/LoopLayout |
8
tudoutiaoya OP @xaoflysho 感谢佬
|