UICollectionView 不自动滚动
Posted
技术标签:
【中文标题】UICollectionView 不自动滚动【英文标题】:UICollectionView not auto scrolling 【发布时间】:2020-10-05 09:16:51 【问题描述】:所以,我有一个用于自动滚动 UICollectionView 的代码(启用分页的水平)。它正在工作。现在,我更新了 Xcode 和 ios,突然,相同的代码不再工作了。我真的没有改变任何其他东西。其他人也遇到过这个问题吗? 此集合视图位于标题可重用视图内。
func setTimer()
let _ = Timer.scheduledTimer(timeInterval: 3.0, target: self, selector: #selector(self.autoScroll), userInfo: nil, repeats: true)
@objc func autoScroll()
print("x is", self.x, self.allBanners.count)
if self.x < self.allBanners.count
self.x = self.x + 1
else
self.x = 1
// DispatchQueue.main.async
self.resuableView.featuredCollectionView?.scrollToItem(at: IndexPath(item: self.x, section: 0), at: .centeredHorizontally, animated: true)
self.resuableView.featuredCollectionView?.setNeedsLayout()
//
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView)
let xPosition = scrollView.contentOffset.x
let w = scrollView.bounds.size.width
self.x = Int(ceil(xPosition/w))
print("dec", self.x)
如果我打印 x 的值,它会正确打印。也就是说,每 3 秒后,它增加 1,但是,该 scrollToItem 不起作用。 另外,如果我禁用分页,那么它可以工作,但是,我确实需要分页。 即使我手动将集合视图滚动到任何项目,只要 @objc func autoScroll() 函数被调用,它也只会将其恢复到第一个项目。
有人知道为什么会这样吗? 附言我已经尝试过不使用异步、使用异步、不使用或使用 setNeedsLayout。 我有 Xcode 版本 12.0.1 (12A7300)
【问题讨论】:
我认为需要将异步调度到主队列,您可以尝试删除 setNeedsLayout 吗? 就像我说的,我已经尝试了所有这些可能的方法。事实上,原来的没有 setNeedsLayout() 或 asyncself.allBanners.count
的值是多少?
那个数是 6
你有这行:self.resuableView.featuredCollectionView?.scrollToItem
... 而?
表示featuredCollectionView
可能无效。你有没有通过调试来确保它是?您能否发布额外的代码 - 足以重现该问题?
【参考方案1】:
我注意到了一些怪癖,尤其是 iOS 14...
如果一个单元格破坏了自动布局,scrollToItemAt
会惨遭失败,以及手动滚动。
这是一个完整的例子:
简单的细胞类
class MyTestCell: UICollectionViewCell
var cView: UIView = UIView()
var theLabel: UILabel = UILabel()
override init(frame: CGRect)
super.init(frame: frame)
commonInit()
required init?(coder: NSCoder)
super.init(coder: coder)
commonInit()
func commonInit() -> Void
// stylize the cell a little with a bordered-rounded-corner view inset by 8-pts
cView.backgroundColor = .cyan
cView.layer.borderWidth = 1
cView.layer.borderColor = UIColor.blue.cgColor
cView.layer.cornerRadius = 8
cView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(cView)
theLabel.translatesAutoresizingMaskIntoConstraints = false
cView.addSubview(theLabel)
let g = contentView.layoutMarginsGuide
NSLayoutConstraint.activate([
cView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
cView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
cView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
cView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
theLabel.topAnchor.constraint(equalTo: cView.topAnchor, constant: 8.0),
theLabel.leadingAnchor.constraint(equalTo: cView.leadingAnchor, constant: 8.0),
theLabel.trailingAnchor.constraint(equalTo: cView.trailingAnchor, constant: -8.0),
theLabel.bottomAnchor.constraint(equalTo: cView.bottomAnchor, constant: -8.0),
])
theLabel.textAlignment = .center
theLabel.numberOfLines = 0
视图控制器类
class AutoScrollViewController: UIViewController
var collectionView: UICollectionView!
var myData: [String] = []
var x: Int = 0
override func viewDidLoad()
super.viewDidLoad()
// create 30 strings
myData = (0..<30).map "Cell \($0)"
// couple cells with longer text for variety
myData[3] = "More text in cell 3"
myData[7] = "The text in cell 7 is long enough to need to wrap onto multiple lines."
// create a flow layout
let f = setupFlowLayout()
// create the collection view
collectionView = UICollectionView(frame: .zero, collectionViewLayout: f)
// we want to use paging
collectionView.isPagingEnabled = true
// register the cell
collectionView.register(MyTestCell.self, forCellWithReuseIdentifier: "cell")
// data source and delgate
collectionView.dataSource = self
collectionView.delegate = self
// add a "Tap instruction" label
let instLabel = UILabel()
instLabel.numberOfLines = 0
instLabel.textAlignment = .center
instLabel.text = "Cells will auto-advance\nevery 3 seconds.\n\nYou can also Tap here\nto jump to Cell 23"
instLabel.translatesAutoresizingMaskIntoConstraints = false
// add UI elements
view.addSubview(collectionView)
view.addSubview(instLabel)
collectionView.translatesAutoresizingMaskIntoConstraints = false
instLabel.translatesAutoresizingMaskIntoConstraints = false
// respect safe area
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// constrain collection view Top / Leading / Trailing + 40-pts
collectionView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
collectionView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
collectionView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),
// collection view Height: 160
collectionView.heightAnchor.constraint(equalToConstant: 160.0),
// constrain instruction label below and centered to the collection view
instLabel.topAnchor.constraint(equalTo: collectionView.bottomAnchor, constant: 40.0),
instLabel.centerXAnchor.constraint(equalTo: collectionView.centerXAnchor),
instLabel.widthAnchor.constraint(equalTo: collectionView.widthAnchor),
])
// for testing, add a tap recognizer to the view
let t = UITapGestureRecognizer(target: self, action: #selector(self.tapScroll))
view.addGestureRecognizer(t)
override func viewDidAppear(_ animated: Bool)
super.viewDidAppear(animated)
// set collection view item size here
if let f = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
f.itemSize = CGSize(width: collectionView.frame.width, height: collectionView.frame.height)
setTimer()
func setTimer()
let _ = Timer.scheduledTimer(timeInterval: 3.0, target: self, selector: #selector(self.autoScroll), userInfo: nil, repeats: true)
@objc func tapScroll()
self.x = 23
collectionView.scrollToItem(at: IndexPath(item: self.x, section: 0), at: .left, animated: true)
@objc func autoScroll()
print("x is", self.x, "Cell Count is", self.myData.count)
self.x = self.x + 1
if self.x >= self.myData.count
self.x = 0
collectionView.scrollToItem(at: IndexPath(item: self.x, section: 0), at: .left, animated: true)
带有数据源和委托实现的扩展
extension AutoScrollViewController: UICollectionViewDataSource, UICollectionViewDelegate
private func setupFlowLayout() -> UICollectionViewFlowLayout
let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .horizontal
flowLayout.sectionInset = .zero
flowLayout.minimumLineSpacing = 0
flowLayout.minimumInteritemSpacing = 1
return flowLayout
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
return myData.count
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
let c = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MyTestCell
// alternate cell background color so we can see it
c.contentView.backgroundColor = indexPath.item % 2 == 0 ? .orange : .yellow
c.theLabel.text = myData[indexPath.item]
return c
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView)
let xPosition = scrollView.contentOffset.x
let w = scrollView.bounds.size.width
self.x = Int(ceil(xPosition/w))
print("dec", xPosition, w, self.x)
没有@IBOutlet
或@IBAction
连接,因此只需为AutoScrollViewController
的自定义类分配一个默认的UIViewController
(来自上述代码)。
【讨论】:
以上是关于UICollectionView 不自动滚动的主要内容,如果未能解决你的问题,请参考以下文章
在 UICollectionView/UITableView 中为滚动视图的偏移设置动画会导致单元格过早消失
如何让 UICollectionView 在不离开屏幕的情况下使用自动布局填充其包含滚动视图的宽度?
如何使用 Timer 在 UITableView 内自动滚动 UICollectionView?