CollectionView 自动移动到下一个单元格

问题描述 投票:0回答:12

我正在尝试创建像 Flipkart 这样的水平滑块。我正在使用具有水平滚动和分页功能的collectionView。单元格包含 imageView。我成功地手动水平滚动项目,但我希望所有这些项目都能自动和手动移动。我不知道如何自动滚动 collectionView 的项目。

我在 viewDidAppear 中使用了这段代码:

let visibleIndexPath: NSIndexPath = self.collectionView.indexPathForCell(cell)!
                
self.collectionView.scrollToItemAtIndexPath(visibleIndexPath,  
atScrollPosition: UICollectionViewScrollPosition.CenteredHorizontally, animated: true)

import UIKit

class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
    
    @IBOutlet var pageControl: UIPageControl!
    @IBOutlet var collectionView: UICollectionView!
    var begin = false
    let image1 = UIImage(named: "Slide 1")
    let image2 = UIImage(named: "Slide 2")
    let image3 = UIImage(named: "Slide 1")
    
    var images = [UIImage]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        images = [image1!, image2!, image3!]
        startTimer()
    }        

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        pageControl.numberOfPages = images.count
        return images.count
    }
    
    var cell : CollectionViewCell1!

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        
      cell = collectionView.dequeueReusableCellWithReuseIdentifier("CollectionViewCell1", forIndexPath: indexPath) as! CollectionViewCell1
        cell.cell_image.image = images[indexPath.row]
        
        return cell
    }
    

    /**
     Scroll to Next Cell
     */
    func scrollToNextCell(){
        
        //get cell size
        let cellSize = CGSizeMake(self.view.frame.width, self.view.frame.height);
        
        //get current content Offset of the Collection view
        let contentOffset = collectionView.contentOffset;
        
            //scroll to next cell
        if begin == true
        {
            pageControl.currentPage == 0
            collectionView.scrollRectToVisible(CGRectZero, animated: true)
            begin = false
        }
        else
        {
            collectionView.scrollRectToVisible(CGRectMake(contentOffset.x + cellSize.width, contentOffset.y, cellSize.width, cellSize.height), animated: true);
        }
        
    }
    
    /**
     Invokes Timer to start Automatic Animation with repeat enabled
     */
    
    func startTimer() {
        
       NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(ViewController.scrollToNextCell), userInfo: nil, repeats: true);
        
        
    }
    
    func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
        
        // If the scroll animation ended, update the page control to reflect the current page we are on
        
        pageControl.currentPage = Int((collectionView.contentOffset.x / collectionView.contentSize.width) * CGFloat(images.count))
        
        if collectionView.contentSize.width == collectionView.contentOffset.x + self.view.frame.width
        {
            begin = true

        }
        
    }
    
    func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) {
        
        // Called when manually setting contentOffset
        scrollViewDidEndDecelerating(scrollView)
        
    }
    
}

这是我的全部代码。我无法转到最后一个单元格之后的第一个单元格。

swift pagination uicollectionview horizontal-scrolling
12个回答
28
投票

下面是您可以尝试的代码:

    /**
     Scroll to Next Cell
     */
    func scrollToNextCell(){

        //get Collection View Instance
        let collectionView:UICollectionView;

        //get cell size
        let cellSize = CGSizeMake(self.view.frame.width, self.view.frame.height);

        //get current content Offset of the Collection view
        let contentOffset = collectionView.contentOffset;

        //scroll to next cell
        collectionView.scrollRectToVisible(CGRectMake(contentOffset.x + cellSize.width, contentOffset.y, cellSize.width, cellSize.height), animated: true);


    }

    /**
     Invokes Timer to start Automatic Animation with repeat enabled
     */
    func startTimer() {

        let timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("scrollToNextCell"), userInfo: nil, repeats: true);


    }

21
投票

对于 Swift4

override func viewDidLoad() {
    super.viewDidLoad()

    startTimer()
}



func startTimer() {

    let timer =  Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.scrollAutomatically), userInfo: nil, repeats: true)
}


@objc func scrollAutomatically(_ timer1: Timer) {

    if let coll  = topMenuCollection {
        for cell in coll.visibleCells {
            let indexPath: IndexPath? = coll.indexPath(for: cell)
            if ((indexPath?.row)! < banner.count - 1){
                let indexPath1: IndexPath?
                indexPath1 = IndexPath.init(row: (indexPath?.row)! + 1, section: (indexPath?.section)!)

                coll.scrollToItem(at: indexPath1!, at: .right, animated: true)
            }
            else{
                let indexPath1: IndexPath?
                indexPath1 = IndexPath.init(row: 0, section: (indexPath?.section)!)
                coll.scrollToItem(at: indexPath1!, at: .left, animated: true)
            }

        }
    }
}

topMenuCollection :- 你的收藏视图

banner.Count:- 包含集合视图的单元格数量


16
投票

斯威夫特3

此测试代码滚动到下一个单元格并返回到最后一项之后的第一项。

func setTimer() {
     let _ = Timer.scheduledTimer(timeInterval: 3.0, target: self, selector: #selector(MainVC.autoScroll), userInfo: nil, repeats: true)
}
var x = 1
@objc func autoScroll() {
    if self.x < self.storiesForCollectionView.count {
      let indexPath = IndexPath(item: x, section: 0)
      self.collectionViewUp.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
      self.x = self.x + 1
    }else{
      self.x = 0
      self.collectionViewUp.scrollToItem(at: IndexPath(item: 0, section: 0), at: .centeredHorizontally, animated: true)
    }
}

override func viewDidLoad() {
        super.viewDidLoad()
        setTimer()
    }

8
投票
/**
 Scroll to Next Cell
 */
func scrollToNextCell(){

    //get cell size
    let cellSize = CGSizeMake(self.view.frame.width, self.view.frame.height);

    //get current content Offset of the Collection view
    let contentOffset = collectionView.contentOffset;

    if collectionView.contentSize.width <= collectionView.contentOffset.x + cellSize.width
    {
        collectionView.scrollRectToVisible(CGRectMake(0, contentOffset.y, cellSize.width, cellSize.height), animated: true);

    } else {
        collectionView.scrollRectToVisible(CGRectMake(contentOffset.x + cellSize.width, contentOffset.y, cellSize.width, cellSize.height), animated: true);

    }

}

/**
 Invokes Timer to start Automatic Animation with repeat enabled
 */
func startTimer() {
    NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: Selector("scrollToNextCell"), userInfo: nil, repeats: true);
}

5
投票
Use your pagecontrol property and scrolltoitem.

func setuptimer() {
  timer = Timer.scheduledTimer(timeInterval: 3, target: self , selector: 
#selector(startScrolling), userInfo: nil, repeats: true)

}

@objc func startScrolling() {

    if pageControl.currentPage == pageControl.numberOfPages - 1 {
        pageControl.currentPage = 0
    } else {
    pageControl.currentPage += 1
    }
    <yourCollectionView>.scrollToItem(at: IndexPath(row: pageControl.currentPage, section: 0), at: .right, animated: true)
}

4
投票

迅捷4:

func scrollToNextCell(){

    //get cell size
    let cellSize = view.frame.size

    //get current content Offset of the Collection view
    let contentOffset = collectionView.contentOffset

    if collectionView.contentSize.width <= collectionView.contentOffset.x + cellSize.width
    {
        let r = CGRect(x: 0, y: contentOffset.y, width: cellSize.width, height: cellSize.height)
        collectionView.scrollRectToVisible(r, animated: true)

    } else {
        let r = CGRect(x: contentOffset.x + cellSize.width, y: contentOffset.y, width: cellSize.width, height: cellSize.height)
        collectionView.scrollRectToVisible(r, animated: true);
    }

}

3
投票

这是我稍微改进的解决方案。当用户手动开始滚动时,它会停止滚动;如果再次重复使用单元格,它会重新启动滚动。

private var indexCurrentCell = 0
private weak var timer: Timer?

private var items = [Item]() {
    didSet {
        collectionView.reloadData()

        indexCurrentCell()
    }
}

private func startAutoscrolling() {
    indexCurrentCell = 0
    timer?.invalidate()
    timer = Timer.scheduledTimer(withTimeInterval: 3, repeats: true) { [weak self] timer in
        guard let self = self else {
            timer.invalidate()
            return
        }

        guard !self.items.isEmpty else {
            return
        }

        if self.indexCurrentCell < self.items.count {
            let indexPath = IndexPath(item: self.indexCurrentCell, section: 0)
            self.collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
            self.indexCurrentCell += 1
        } else {
            self.indexCurrentCell = 1
            self.collectionView.scrollToItem(at: IndexPath(item: 0, section: 0), at: .centeredHorizontally, animated: true)
        }
    }
    timer?.fire()
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if scrollView.isTracking {
        timer?.invalidate()
    }
}

override func awakeFromNib() {
    super.awakeFromNib()

    startAutoscrolling()
}

3
投票

在 Swift 4 及以上版本中,我添加了以下代码并且工作得很好。当我们手动滚动时,计时器停止,当手动滚动结束时,计时器再次从最后滚动的索引开始。

将变量初始化为:-

 private var timer: Timer?
 private var indexCurrentCell = 0

然后在类或扩展中添加以下代码,如下所示:-

func scrollViewWillBeginDragging(scrollView: UIScrollView) {
    self.stopTimer()
}

func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    self.startTimerForAutoScroll()
}

private func startTimerForAutoScroll() {
    self.startAutoScroll()
}

private func stopTimer() {
    timer?.invalidate()
    timer = nil
}

private func startAutoScroll() {
    indexCurrentCell = 0
    timer?.invalidate()
    timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { [weak self] timer in
        guard let self = self else {
            timer.invalidate()
            return
        }
        
        guard let offersDataArr = self.offersData, !offersDataArr.isEmpty else {
            return
        }
        
        if self.indexCurrentCell < offersDataArr.count {
            let indexPath = IndexPath(item: self.indexCurrentCell, section: 0)
            self.offersCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
            self.indexCurrentCell += 1
        } else {
            self.indexCurrentCell = 1
            self.offersCollectionView.scrollToItem(at: IndexPath(item: 0, section: 0), at: .centeredHorizontally, animated: true)
        }
    }
    timer?.fire()
}

并调用函数(startTimerForAutoScroll),从这里设置集合视图数组:-

 override func viewDidLoad() {
    super.viewDidLoad()
      offersCollectionView.delegate = self
      offersCollectionView.dataSource = self
      startTimerForAutoScroll()
}

2
投票

试试这个

var index = 0
var inForwardDirection = true
var timer: Timer?

@objc func scrollToNextCell() {

    //scroll to next cell
    let items = collectionViewTable.numberOfItems(inSection: 0)
    if (items - 1) == index {
        collectionViewTable.scrollToItem(at: IndexPath(row: index, section: 0), at: UICollectionViewScrollPosition.right, animated: true)
    } else if index == 0 {
        collectionViewTable.scrollToItem(at: IndexPath(row: index, section: 0), at: UICollectionViewScrollPosition.left, animated: true)
    } else {
        collectionViewTable.scrollToItem(at: IndexPath(row: index, section: 0), at: UICollectionViewScrollPosition.centeredHorizontally, animated: true)
    }

    if inForwardDirection {
        if index == (items - 1) {
            index -= 1
            inForwardDirection = false
        } else {
            index += 1
        }
    } else {
        if index == 0 {
            index += 1
            inForwardDirection = true
        } else {
            index -= 1
        }
    }

}

/**
 call this method when collection view loaded
 */
func startTimer() {
    if timer == nil {
        timer = Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(scrollToNextCell), userInfo: nil, repeats: true);
    }
}

1
投票

我建议使用集合视图方法

scrollToItem(at:at:animated:)
而不是scrollRectToVisible。它使您不必进行计算来确定要公开的矩形。您只需指定要滚动到的索引路径即可。


0
投票
 /**
 Scroll to Next Cell
 */
@objc func scrollToNextCell(){



    //get cell size
    let cellSize = CGSize(width:self.view.frame.size.width, height:viewForCV.frame.size.height)


    //get current content Offset of the Collection view
    let contentOffset = cvAdvertisements.contentOffset;

    if cvAdvertisements.contentSize.width <= cvAdvertisements.contentOffset.x + cellSize.width
    {
        cvAdvertisements.scrollRectToVisible(CGRect(x:0, y:contentOffset.y, width:cellSize.width, height:cellSize.height), animated: true);

    } else {

        cvAdvertisements.scrollRectToVisible(CGRect(x:contentOffset.x + cellSize.width, y:contentOffset.y, width:cellSize.width, height:cellSize.height), animated: true);

    }

}

/**
 Invokes Timer to start Automatic Animation with repeat enabled
 */
func startTimer() {

    Timer.scheduledTimer(timeInterval: 2.0, target: self, selector: #selector(LoginViewController.scrollToNextCell), userInfo: nil, repeats: true);

}

0
投票

您可以使用这个 AutoScrollCollectionView cocoapod 来实现在特定间隔内自动滚动

就像从 AutoScrollCollectionView 继承集合视图并调用 startAutoScrolling 方法一样简单,如下所示

self.autoScrollCollectionView.startAutoScrolling(withTimeInterval: TimeInterval(exactly: 2.0)!)

self.autoScrollCollectionView.stopAutoScrolling()
© www.soinside.com 2019 - 2024. All rights reserved.