CollectionView move to next cell automatically swift
Asked Answered
T

12

22

I am trying to create horizontal slider like Flipkart. I am using collectionView with Horizontal scrolling and paging. Cell contains imageView. I am succeed in scrolling items horizontally manually, but I want all these items to move automatic and manually both. I am not getting how to scroll items of collectionView automatically. Please guide me to do this.

I have use this code in viewDidAppear:

let visibleIndexPath: NSIndexPath = self.collectionView.indexPathForCell(cell)!

self.collectionView.scrollToItemAtIndexPath(visibleIndexPath,  
atScrollPosition: UICollectionViewScrollPosition.CenteredHorizontally, animated: true)

Thanks.

EDIT:

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)

    }

}

This is my whole code.. I am not able to go to first cell after last cell. Please Help me.

Translative answered 13/4, 2016 at 4:57 Comment(2)
you can use NSTimer with 1 second delay and animate to next cell index.Medullary
Yah.. but I am not getting how to use NSTimer with collectionView to move cell. Can u help me?Translative
M
28

Below is code you can try :

    /**
     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);


    }
Medullary answered 13/4, 2016 at 6:14 Comment(5)
ok.. Thanks. this worked! but I want that after last cell it should go to first cell..Translative
all you can do is check the contentSize of CollectionView if its equal to contentOffset+cellSize then scroll to CGRectZeroMedullary
I am not able to go to first page.. I did as you said.. @ Babul PrabhakarTranslative
try this if collectionView.contentSize.width <= collectionView.contentOffset.x + self.view.frame.width { begin = true }Medullary
@BabulPrabhakar Can you please help me I want to implement it in multiple collection views inside table view how can I do it?Hardfeatured
T
21

For 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 :- your collection view

banner.Count:- a number of cells containing a collection view

Tumult answered 30/4, 2018 at 8:53 Comment(2)
working thanks! : small edit with added correction to previous "< <" with "<"Alleneallentown
I am always scared when I see so many forced unwrappings!Nuncio
O
16

Swift 3

This tested code scrolls to the next cell and returns to first item after the last one.

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()
    }
Occasional answered 12/9, 2017 at 13:41 Comment(2)
Actually the code should be else { self.x = 1 self.collectionViewUp.scrollToItem(at: IndexPath(item: 0, section: 0), at: .centeredHorizontally, animated: true) } Thanks for your input.Fpc
Can you Please Help me to use this code for multiple collection view inside the table view cellHardfeatured
S
7
/**
 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);
}
Susette answered 15/4, 2016 at 10:51 Comment(0)
Y
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)
}
Yandell answered 29/1, 2020 at 17:1 Comment(0)
D
4

swift 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);
    }

}
Dmz answered 12/4, 2018 at 9:28 Comment(0)
B
3

Here is my slightly improved solution. It stops the scroll when user manually starts to scroll and restarts it if the cell is reused again.

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()
}
Bitterling answered 29/4, 2019 at 11:47 Comment(0)
D
3

In Swift 4 & above, I have added the following code and works perfectly fine. While we scroll manually the timer has stop and when end scrolling manually then timer again starts from last index scrolled.

Initialise the variable as:-

 private var timer: Timer?
 private var indexCurrentCell = 0

Then add following code in the class or extension as follows:-

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

And call the function(startTimerForAutoScroll), from where the collection view array setup:-

 override func viewDidLoad() {
    super.viewDidLoad()
      offersCollectionView.delegate = self
      offersCollectionView.dataSource = self
      startTimerForAutoScroll()
}
Ducky answered 20/4, 2022 at 8:4 Comment(0)
D
2

try this

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);
    }
}
Devolution answered 21/3, 2019 at 18:17 Comment(1)
i want if collectionview reaches to last image then it should display first image from arrayReservation
O
1

I suggest using the collection view method scrollToItem(at:at:animated:) rather than scrollRectToVisible. It saves you from having to do calculations to figure out what rectangle to expose. You can just specify an indexPath to which you want to scroll.

Outage answered 15/12, 2016 at 15:55 Comment(3)
I have a UICollectionView and it's scroll direction is horizontal. I need to move the collection cells from right to left automatically. Can you please help me to do that with scrollToItem(at:at:animated:)? @Duncan CNerva
how can i specify a particular indexpath?Iroquoian
The full name of the function is func scrollToItem(at indexPath: IndexPath, at scrollPosition: UICollectionViewScrollPosition, animated: Bool). It takes an IndexPath, as well as a scroll position. Look up that function in the Xcode API docs for more information.Outage
V
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);

}
Vendor answered 24/8, 2018 at 10:32 Comment(0)
F
0

You can achieve that using this AutoScrollCollectionView cocoapod to scroll automatically within specific intervals

It is as simple as subclassing your collection view from AutoScrollCollectionView and call startAutoScrolling method as shown below

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

self.autoScrollCollectionView.stopAutoScrolling()
Feininger answered 5/1, 2021 at 4:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.