为啥在 Swift 中 CollectionView 函数被调用了两次?
Posted
技术标签:
【中文标题】为啥在 Swift 中 CollectionView 函数被调用了两次?【英文标题】:Why is the CollectionView function called twice in Swift?为什么在 Swift 中 CollectionView 函数被调用了两次? 【发布时间】:2020-02-07 05:57:52 【问题描述】:我在函数被调用 2 次时遇到问题。因此,PageView 中的值设置不正确,因为索引值不正确。如何正确控制?
ViewController.swift
class ViewController: UIViewController
@IBOutlet weak var collectionView: UICollectionView!
@IBOutlet weak var pageView: UIPageControl!
@IBOutlet var guideView: UIView!
var step : Int! = 0
var beforeStep : Int! = 0
var imageArray = [UIImage(named: "swipe1"),
UIImage(named: "swipe2"),
UIImage(named: "swipe3"),
UIImage(named: "swipe4"),
UIImage(named: "swipe5")]
override func viewDidLoad()
super.viewDidLoad()
pageView.numberOfPages = imageArray.count
pageView.currentPage = 0
pageView.currentPageIndicatorTintColor = UIColor.color(.dacColor)
pageView.pageIndicatorTintColor = UIColor.gray
view.backgroundColor = UIColor(red: CGFloat(252.0/255.0), green: CGFloat(251.0/255.0), blue: CGFloat(245.0/255.0), alpha: CGFloat(1.0))
collectionView.backgroundColor = UIColor(red: CGFloat(252.0/255.0), green: CGFloat(251.0/255.0), blue: CGFloat(245.0/255.0), alpha: CGFloat(1.0))
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
return imageArray.count
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
if let vc = cell.viewWithTag(111) as? UIImageView
vc.image = imageArray[indexPath.row]
if let ab = guideView.viewWithTag(222) as? UIPageControl
ab.currentPage = indexPath.row - 1
return cell
extension ViewController: UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
let size = collectionView.frame.size
return CGSize(width: size.width, height: size.height)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat
return 0
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat
return 0
有问题的功能部分
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
if let vc = cell.viewWithTag(111) as? UIImageView
vc.image = imageArray[indexPath.row]
if let ab = guideView.viewWithTag(222) as? UIPageControl
ab.currentPage = indexPath.row - 1
return cell
StoryBoard 中的 CollectionView
在 Storyboard 中查看列表
我希望将 PageController 标记为与图片的位置相匹配。
有没有人和我一样的问题解决过?
【问题讨论】:
你需要将 UIPageControl 放在集合视图之外(在主视图中),当你滚动时,你需要使用滚动代理找到索引 @SiddhantNigam 我将图片更新为问题。如您所见,PageController 不在 CollectionView 中。 @SiddhantNigam 我应该如何使用滚动委托?告诉我答案。 试试 FSPagerView 很简单:github.com/WenchaoD/FSPagerView 如果你不喜欢这个试试这个,然后我会分享你收集视图的代码 【参考方案1】:collectionView(_:cellForItemAt:)
是一个集合视图委托方法,它往往会被多次调用,触发调用的因素很多,例如:
可见单元格的数量,取决于集合的高度
滚动单元格以重复使用它们时
或触发更改/刷新集合,如:
reloadData()
、reloadItems(at:)
或 reloadSections(_:)
可能是来自包含此集合视图的视图的layoutIfNeeded()
调用。
还有更多...
关键是,函数被多次调用是很正常的。您的答案可能在于“什么触发了通话?”
编辑:
根据集合的索引更新你的pageControl:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView)
let visibleRect = CGRect(origin: yourCollectionView.contentOffset, size: yourCollectionView.bounds.size)
let midPointOfVisibleRect = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
if let visibleIndexPath = yourCollectionView.indexPathForItem(at: midPointOfVisibleRect)
yourPageControl.currentPage = visibleIndexPath.row
如果您仅将UIPageViewController
用于页面指示,则应使用UIPageControl
。您可能还需要设置yourCollectionView.isPagingEnabled = true
,因为这更适合页面控件。
【讨论】:
不能正常控制PageController吗? 好的,刚刚看到您编辑的问题。这是为了解释函数调用。那么,你需要根据你的集合视图单元格的索引来更新页面控件吗?? 是的,PageController的值必须设置成与图片的索引值相匹配。 我应该在哪里使用你添加的功能? @hongdeveloper 我已经设置了 isPagingEnabled。谢谢你,我解决了这个问题。【参考方案2】:在集合视图中转到布局并选择自定义:
class CustomCollectionViewFlowLayout: UICollectionViewFlowLayout
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint
if let collectionViewBounds = self.collectionView?.bounds
let halfWidthOfVC = collectionViewBounds.size.width * 0.5
let proposedContentOffsetCenterX = proposedContentOffset.x + halfWidthOfVC
if let attributesForVisibleCells = self.layoutAttributesForElements(in: collectionViewBounds)
var candidateAttribute : UICollectionViewLayoutAttributes?
for attributes in attributesForVisibleCells
let candAttr : UICollectionViewLayoutAttributes? = candidateAttribute
if candAttr != nil
let a = attributes.center.x - proposedContentOffsetCenterX
let b = candAttr!.center.x - proposedContentOffsetCenterX
if fabs(a) < fabs(b)
candidateAttribute = attributes
else
candidateAttribute = attributes
continue
if candidateAttribute != nil
return CGPoint(x: candidateAttribute!.center.x - halfWidthOfVC, y: proposedContentOffset.y);
return CGPoint.zero
然后在委托中:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView)
var visibleRect = CGRect()
visibleRect.origin = Collections.contentOffset
visibleRect.size = Collections.bounds.size
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
guard let indexPath = Collections.indexPathForItem(at: visiblePoint) else return
print(indexPath.item)
【讨论】:
我不知道如何使用你在我的代码中扩展的类。 你复制粘贴我给你的课程吗? 是的,我把你给我的课程做了一个文件并复制了。 现在点击storyBoard中的collectionView,你会看到默认布局是流动的,然后你点击并选择自定义,然后文本字段将在那里写下类名并按回车 该类将帮助您滚动中心,scrollViewDidEndDecelerating 帮助您在滚动完成后获取索引路径以上是关于为啥在 Swift 中 CollectionView 函数被调用了两次?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 CFStringEncodings 在 Swift 中没有 UTF8?
为啥某些 Swift 标准库函数在 Playground 中无法识别?