简体   繁体   English

为什么在 Swift 中 CollectionView 函数会被调用两次?

[英]Why is the CollectionView function called twice in Swift?

I am having trouble with the function being called 2 times.我在调用函数 2 次时遇到问题。 Because of this, the value in PageView is not set properly because the index value is not correct.因此,PageView 中的值设置不正确,因为索引值不正确。 How can you control this correctly?你怎么能正确地控制它?

ViewController.swift视图控制器.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
    }
}

problematic function part有问题的功能部分

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
    }

CollectionView in StoryBoard StoryBoard 中的 CollectionView

在此处输入图片说明

View List in Storyboard在故事板中查看列表

在此处输入图片说明

I want the PageController to be marked to match the location of the picture.我希望将 PageController 标记为匹配图片的位置。

Has anyone solved the same problem as me?有没有人解决过和我一样的问题?

collectionView(_:cellForItemAt:) is a collection view delegate method which tends to get called more than once, and there are a lot of factors that trigger the call like: collectionView(_:cellForItemAt:)是一个集合视图委托方法,它往往会被多次调用,并且有很多因素会触发调用,例如:

  1. The number of visible cells you've got, depending on the height of the collection您拥有的可见单元格的数量,取决于集合的高度

  2. When scrolling through cells to reuse them滚动单元格以重用它们时

Or triggers to change/refresh the collection like:或触发更改/刷新集合,例如:

  1. reloadData() , reloadItems(at:) or reloadSections(_:) reloadData()reloadItems(at:)reloadSections(_:)

  2. Perhaps a layoutIfNeeded() call from the view that contains this collection view.也许来自包含此集合视图的视图的layoutIfNeeded()调用。

and more...和更多...

The point is, the function getting called more than once is pretty normal.关键是,函数被多次调用是很正常的。 Your answer probably lies in "What triggers the call?"您的答案可能在于“是什么触发了呼叫?”

EDIT :编辑

To update your pageControl according to the index of the collection:要根据集合的索引更新您的 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
   }
}

If you're using a UIPageViewController just for the page indication, a UIPageControl should do.如果您仅将UIPageViewController用于页面指示,则应使用UIPageControl You might also have to set yourCollectionView.isPagingEnabled = true as that would be more appropriate for a page control.您可能还必须设置yourCollectionView.isPagingEnabled = true因为这更适合页面控件。

In collection view go to layout and select custom:在集合视图中转到布局并选择自定义:

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
}
}

and then in delegate:然后在委托中:

 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)

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM