【问题标题】:How to add PageControl inside UICollectionView Image Scrolling如何在 UICollectionView 图像滚动中添加 PageControl
【发布时间】:2017-04-19 21:47:28
【问题描述】:

我有UICollectionView 水平图像列表代码。我想在显示滚动图像时添加PageControl,我添加了页面控制选择器和IBOutlet,但是如何在UICollecitonView 之间集成它?

我的代码如下:

 class  ViewController: UIViewController,  UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {


    @IBOutlet weak var View : DesignableView!


    @IBOutlet var collectionView: UICollectionView!
    @IBOutlet var collectionViewLayout: UICollectionViewFlowLayout!

    @IBOutlet open weak var pageControl: UIPageControl? {
        didSet {
            pageControl?.addTarget(self, action: #selector(ViewController.pageChanged(_:)), for: .valueChanged)
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

         pageControl?.numberOfPages = 11


    }


    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 11;
    }




    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell: ImageCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCollectionViewCell", for: indexPath) as! ImageCollectionViewCell
        cell.label.text = "Cell \(indexPath.row)"
        cell.backgroundImageView.image = UIImage(named: "Parallax \(indexPath.row + 1)")

        // Parallax cell setup
        cell.parallaxTheImageViewScrollOffset(self.collectionView.contentOffset, scrollDirection: self.collectionViewLayout.scrollDirection)
        return cell
    }



    @IBAction open func pageChanged(_ sender: UIPageControl) {

        print(sender.currentPage)


    }




    // MARK: Delegate

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return collectionView.bounds.size;
    }

    // MARK: Scrolling

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        // Parallax visible cells
        for cell: ImageCollectionViewCell in collectionView.visibleCells as! [ImageCollectionViewCell] {
            cell.parallaxTheImageViewScrollOffset(self.collectionView.contentOffset, scrollDirection: self.collectionViewLayout.scrollDirection)
        }
    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }



}

【问题讨论】:

    标签: ios swift uicollectionview swift3 uipagecontrol


    【解决方案1】:
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let OFFSet = scrollView.contentOffset.x
        let width = scrollView.frame.width
        let horizontalCenter = width / 2
        pageviewControl.currentPage = Int(OFFSet + horizontalCenter) / Int(width)
    }
    

    【讨论】:

      【解决方案2】:

      只需添加此功能

      func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView){
          //Test the offset and calculate the current page after scrolling ends
          let pageWidth:CGFloat = scrollView.frame.width
          let currentPage:CGFloat = floor((scrollView.contentOffset.x-pageWidth/2)/pageWidth)+1
          //Change the indicator
          self.pageControl.currentPage = Int(currentPage);
      }
      

      【讨论】:

      • 在回答一个三年前的问题和其他八个答案时,您需要解释您的答案有什么新的地方和不同之处。代码块的正确格式与将每一行格式化为内联代码的一部分不同。仅代码答案需要解释它们的工作方式和原因。
      • 这是另一种方法,如果你可以比较另一个
      【解决方案3】:

      swift 5 示例:

      根据CollectionView的Index设置pageController CurrentPage的函数:

      func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
         let visibleRect = CGRect(origin: self.collectionView.contentOffset, size: self.collectionView.bounds.size)
         let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
         if let visibleIndexPath = self.collectionView.indexPathForItem(at: visiblePoint) {
                  self.pageController.currentPage = visibleIndexPath.row
         }
      }
      

      PageControllerAction 函数在选择 PageController 时滚动 CollectionView:

      @IBAction func pageControllerAction(_ sender: UIPageControl) {
             self.collectionView.scrollToItem(at: IndexPath(row: sender.currentPage, section: 0), at: .centeredHorizontally, animated: true)
      }
      

      【讨论】:

        【解决方案4】:

        Swift 5 运行非常流畅

        //MARK:- For Display the page number in page controll of collection view Cell
        func scrollViewDidScroll(_ scrollView: UIScrollView) {
            let visibleRect = CGRect(origin: self.collectionview.contentOffset, size: self.collectionview.bounds.size)
            let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
            if let visibleIndexPath = self.collectionview.indexPathForItem(at: visiblePoint) {
                self.pageControl.currentPage = visibleIndexPath.row
            }
        }
        

        【讨论】:

        • fyi 行用于表格视图,项目用于集合视图。
        • @RickvanderLinde 即使它被称为 row 而不是 item 它也可以正常工作。
        • 如果我们禁用 UIPageControl 的用户交互,这会很顺利。需要支持pagecontrol的action的,把这个计算放在scrollViewDidEndDecelerating
        【解决方案5】:
         func scrollViewDidScroll(_ scrollView: UIScrollView) {
                let visibleRect = CGRect(origin: self.cvImageListing.contentOffset, size: self.cvImageListing.bounds.size)
                let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
                if let visibleIndexPath = self.cvImageListing.indexPathForItem(at: visiblePoint) {
                    self.pageControl.currentPage = visibleIndexPath.row
                }
            }
        

        【讨论】:

          【解决方案6】:

          Luke's answer 对我来说是一个好的开始,但它有两个问题:它没有经常更新(已经在其他答案中指出)但最重要的是它没有为我的收藏视图中的最后一项显示正确的页面(水平方向),并且仅在项目快要离开屏幕时才切换页面。

          正如其他人所说,对于第一个问题,使用scrollViewDidScroll 提供了更好的体验。我担心如此频繁地拨打电话会导致性能问题,但没有注意到任何问题。

          至于第二个问题,对于我的用例,找到位于屏幕中心的单元格的 indexPath 提供了更好的解决方案。请记住,如果您的用例可以在屏幕上容纳两个以上的单元格,则可能需要进行调整。这是因为您的最后一个单元格永远不会到达屏幕中间。我会争辩说,在这种情况下,使用UIPageControl 可能并不理想。

          func scrollViewDidScroll(_ scrollView: UIScrollView) {
              let visibleRect = CGRect(origin: self.collectionView.contentOffset, size: self.collectionView.bounds.size)
              let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
              if let visibleIndexPath = self.collectionView.indexPathForItem(at: visiblePoint) {
                  self.pageControl.currentPage = visibleIndexPath.row
              }
          }
          

          【讨论】:

            【解决方案7】:

            对于响应速度更快的 UIPageControl,我更喜欢使用 scrollViewDidScroll 并计算相对于 scrollView 水平中心的偏移量。

            func scrollViewDidScroll(_ scrollView: UIScrollView) {
                let offSet = scrollView.contentOffset.x
                let width = scrollView.frame.width
                let horizontalCenter = width / 2
            
                pageControl.currentPage = Int(offSet + horizontalCenter) / Int(width)
            }
            

            【讨论】:

            • 最佳解决方案!反应灵敏且准确
            • 明显优于使用滞后的scrollViewDidEndDecelerating 解决方案。
            • Luke 的解决方案不知何故对我不再有效。但是大卫的回答很有效,它救了我的命,ty。
            【解决方案8】:

            等待scrollViewDidEndDecelerating 会导致UIPageControl 更新缓慢。如果您想要响应更快的 UI,我建议您改为实现 scrollViewWillEndDragging(_:withVelocity:targetContentOffset:)

            每个集合视图部分都是一个页面的 Swift 4 示例:

            override func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
                if let collectionView = scrollView as? ScoreCollectionView,
                    let section = collectionView.indexPathForItem(at: targetContentOffset.pointee)?.section {
                    self.pageControl.currentPage = section
                }
            }
            

            【讨论】:

            • 这应该是唯一被接受的答案,因为它是最干净和响应最快的方式。
            • 我必须用section 代替item
            • 如果滑动速度足够快,当前页面可能会产生错误的结果。
            【解决方案9】:

            我不喜欢接受的答案。 willDisplay cell会不时根据用户交互返回错误的页面控件页面。

            我用什么:

            func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
                pageControl.currentPage = Int(scrollView.contentOffset.x) / Int(scrollView.frame.width)
            }
            

            这将在用户完成滚动后更新页面,从而使pageControlcurrentPage 更准确。

            【讨论】:

            • 随心所欲地工作。谢谢
            • 应该是最佳答案
            • 如何使其与从右到左的 pageControl 一起工作?
            • 一整天的精彩搜索终于得到了很好的答案
            • 这应该是公认的答案,说真的我已经看到上面的答案了,我花了大约 3 个小时才意识到正确答案在公认的下面
            【解决方案10】:

            这里你有一个在水平集合视图中带有页面控制分页的完整类。 这正在我的一个应用程序上工作,现在,并且工作正常。如果你不能让它工作,请随时问我,我会帮助你。

            首先,您必须在 Storyboard 中设置您的 CollectionView:

            布局:流
            滚动方向:水平
            启用滚动
            启用分页

            @IBOutlet weak var collectionView: UICollectionView! //img: 77
            
            @IBOutlet weak var pageControl: UIPageControl!
            
            var thisWidth:CGFloat = 0
            
            override func awakeFromNib() {
                super.awakeFromNib()
            
                thisWidth = CGFloat(self.frame.width)
                collectionView.delegate = self
                collectionView.dataSource = self
            
                pageControl.hidesForSinglePage = true
            
            }
            
            func numberOfSections(in collectionView: UICollectionView) -> Int {
                return 10
            }
            
            func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
                return 1
            }
            
            func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YourCell", for: indexPath)
            
                return cell
            }
            
            func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
                self.pageControl.currentPage = indexPath.section
            }
            
            func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
                thisWidth = CGFloat(self.frame.width)
                return CGSize(width: thisWidth, height: self.frame.height)
            }
            

            【讨论】:

            • 当我添加 func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return self.myarray.count // 这里不工作页面控件时,dude 不能使用 pagecontrol }
            • 那是因为要为每个项目制作一个页面,您必须使用部分,而不是行
            • 但是在这个解决方案中,当用户滑动到下一页,然后在没有抬起手指的情况下再次向后滑动时,pageControl 会显示错误的页面。我认为您应该考虑@luke 的回答
            • 这是您应该在回答中明确说明的内容
            猜你喜欢
            • 1970-01-01
            • 2020-11-10
            • 1970-01-01
            • 2018-06-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多