1

So I have a collection view of cards, and what I want is when I swipe left I want the next item to be centered in the middle, this doesn't work with paging enabled

enter image description here

So when I swipe left I want the next card to be centered, this doesn't work with the normal behaviour because I just want to swipe one card.

So I have added UISwipeGestureRecognizer and disabled scrolling on the collection view

class ViewController: UIViewController,UICollectionViewDataSource {

@IBOutlet var joke_cards: UICollectionView!

override func viewDidLoad() {

    super.viewDidLoad();


    //Add gestures
    let leftSwipeGest = UISwipeGestureRecognizer(target: self, action: #selector(funcForGesture))
    leftSwipeGest.direction = .left
    joke_cards.addGestureRecognizer(leftSwipeGest)

}

func funcForGesture(sender: UISwipeGestureRecognizer){
    if sender.direction == .left {
        //scroll to next item
    }
}

Now my problem is how can I scroll to the next item? since I don't know the indexPath? because if I want to use this self.joke_cards.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true), I will need the index path, so I think I need to figure out the current indexPath on the view and add one when the user swipes.

Any suggestions?

//updated So I have managed to get it to work, but it only works when I swipe the first time:

func funcForGesture(sender: UISwipeGestureRecognizer){
    if sender.direction == .left {
        //scroll to next item
        let cellItems = self.joke_cards.indexPathsForVisibleItems
        let next = cellItems[0] as! IndexPath

        self.joke_cards.scrollToItem(at: next, at: .centeredHorizontally, animated: true)
    }
}
Uffo
  • 8,424
  • 20
  • 78
  • 148

3 Answers3

1

One solution:

1: Add an NSIndexPath property to your cells and just set the indexPath to the property in your cellForItem method.

2: Get an array of visible cells.

3: Get the rect of the visible cells and calculate their position on the screen and you can allso get the correct indexPath from the cell property.

Second solution:

1: Add a UILongPressGestureRecognizer to your cell contentView

2: Set minimumPressDuration to 0.

3: Add delegate methods to fire acitons or this.

Third solution:

1: Keep your swipe gesture.

2: And use this method (same as option 2) indexPathForItemAtPoint:

Community
  • 1
  • 1
  • I got it to work, check my updated post, but it only works for the first swipe, what am I doing wrong? Thank you! – Uffo Feb 15 '17 at 11:17
  • @Uffo I'm glad it worked. I don't know what is not working for you? Does the swipe method fire at all? I think maybe you should handle the different state gestures before firing the action : https://developer.apple.com/reference/uikit/uigesturerecognizerstate/uigesturerecognizerstatebegan , this is just the Began, you should handle them all correctly as you see fit. –  Feb 15 '17 at 11:22
  • Yes it works, it swipes but only the first time, the second time doesn't do anything, the method fires, I put a debug message, i think is because of let next = cellItems[0] as! IndexPath i think the index key needs to be updated each time, and I don't know how, the second time it should be [cellItems][1] – Uffo Feb 15 '17 at 11:26
  • @Uffo when you receive the cell in the array Use this method to get the indexPath: let indexPath = self.collectionView.indexPath(for: cell) , note that you can check the indexPaths for multiple cells and just compare them and see which one is the "highest" indexPath.item or "lowest" depending on you want to swipe right or left. Since you will always get 3 items that are visible based on your image. You can also try "lastItem" of the array or "firstItem", see what works for you best –  Feb 15 '17 at 11:35
  • You got me confused, it doesn't work like this: func funcForGesture(sender: UISwipeGestureRecognizer){ if sender.direction == .left { //scroll to next item let cellItems = self.joke_cards.indexPathsForVisibleItems let indexPath = self.joke_cards.indexPath(for: cellItems) self.joke_cards.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true) } } – Uffo Feb 15 '17 at 11:41
  • @Uffo **let cellItems** returns an NSArray with your visible cells, you need to get the actual Cell from the array as I mentioned. https://developer.apple.com/reference/foundation/nsarray/1412852-firstobject for the first object, or https://developer.apple.com/reference/foundation/nsarray/1408316-lastobject for the last object , you do this with **cellItems.first** and **cellItems.last** –  Feb 15 '17 at 11:45
0

Why are you saying that this does not work with paging enabled? This should actually be the best way to do it in my opinion. You can just make the width of the UICollectionViewCells to be equal to the width of the UICollectionView, set the scroll direction to be horizontal and enable paging, that should do the trick.

In this way you won't need any UIGestureRecognizers.

Stefan Stefanov
  • 789
  • 6
  • 23
  • Well it works... but it can scroll multiple items at one time, and I don't want that – Uffo Feb 15 '17 at 11:24
  • That shouldn't be the case. The whole idea behind paging is to scroll only a single view at a time. I have used it multiple times and it worked. This is even the definition provided by apple: "The UIScrollView class supports a paging mode, which restricts a user initiated scroll action to scrolling a single screens worth of content at a time. This mode is used when displaying sequential content, such as an eBook or a series of instructions." – Stefan Stefanov Feb 15 '17 at 11:55
0

Ok so the solution is this one:

@IBOutlet var joke_cards: UICollectionView!

override func viewDidLoad() {

    super.viewDidLoad();


    //Add gestures
    let leftSwipeGest = UISwipeGestureRecognizer(target: self, action: #selector(funcForGesture))
    leftSwipeGest.direction = .left
    joke_cards.addGestureRecognizer(leftSwipeGest)

}

func funcForGesture(sender: UISwipeGestureRecognizer){
    if sender.direction == .left {
                    //scroll to next item
            let cellItems = self.joke_cards.indexPathsForVisibleItems

            self.joke_cards.scrollToItem(at: cellItems.max()!, at: .centeredHorizontally, animated: true)
    }
}
Uffo
  • 8,424
  • 20
  • 78
  • 148