0

I have a collection view, and I am trying to get the index of the cell that I am peeking and poping from.

Issue

Currently I am using indexPathForItemAtPoint: however this always returns 0 no mater where I tap on the screen.

Code

collection view controller:

- (void)viewDidLoad {
    [super viewDidLoad];
    [self registerForPreviewingWithDelegate:self sourceView:self.collectionView];
}

- (UIViewController *) previewingContext:(id <UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location {

    CellEditViewController *CEVC = [self.storyboard instantiateViewControllerWithIdentifier:@"detail"]; //The view I want peek/pop to
    
    NSLog(@"Location: %f,%f", location.x, location.y);
    NSLog(@"Index of: %lu", [[self.collectionView indexPathForItemAtPoint:location] row]);
    
    [CEVC setPreferredContentSize:CGSizeMake(0.0, 320.0)];

    return CEVC;
}

- (void)previewingContext:(id <UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit {
    [self showViewController:viewControllerToCommit sender:self];
}

What I have tried

  • Creating a new location to identify the index cell.
  • Moving registerForPreviewingWithDelegate:sourceView: to where I create each cell.
  • Moving previewingContext:viewControllerForLocation: and previewingContext:commitViewController: to the cell view method, this did not work for other reasons.

I do not think this is an issue with previewing, because when I implemented the same thing with a UITapGestureRecognizer, I got a similar output:

Tap recognizer:

- (void) processDoubleTap:(UITapGestureRecognizer *)sender {
    NSLog(@"Got tapped twice");
    
    if (sender.state == UIGestureRecognizerStateEnded) {
        CGPoint point = [sender locationInView:self.collectionView];
        NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:point];
        
        NSLog(@"Index was: %lu", [indexPath row]);
        
        if (indexPath) {
            NSLog(@"Index was double tapped");
        }
    }
}

Output:

2017-12-25 10:48:13.990523-0800 quickthings[3052:356150] Got tapped twice
2017-12-25 10:48:13.990843-0800 quickthings[3052:356150] Index was: 0

Source

Github Repository

Screenshot

Here is what does happen, this is exactly what I want. The only other thing I would like to do is when the cell is tapped also be able to get the index of the tapped cell.

enter image description here

Collection View In Story Board

The (blue) UIView is "linked" to the Collection View Controller (the top view controller in the second screenshot below).

enter image description here enter image description here

Community
  • 1
  • 1
zoecarver
  • 5,523
  • 2
  • 26
  • 56
  • `[self registerForPreviewingWithDelegate:self sourceView:self.collectionview];` instead? (see this: https://stackoverflow.com/questions/33002637/3d-touch-peek-and-pop-from-uitableviewcell-how-to-hand-over-data-to-other-uiview#comment57133468_33055074) – Larme Dec 22 '17 at 16:24
  • Thanks for the suggestion, but still same issue :( – zoecarver Dec 22 '17 at 16:40
  • I've not used this functionality before so I setup a very basic test (in Swift but that shouldn't matter) and it worked as you are expecting. That leads me to believe it's something outside what you have shown. Do you have any more information (code, examples, etc) that might help throw some light on it? – Upholder Of Truth Dec 25 '17 at 01:59
  • @UpholderOfTruth I have added the repo and a screenshot, is this helpful? If you want me to add anything else just let me know. Thanks for helping! – zoecarver Dec 25 '17 at 18:39
  • I've had a quick look and your issues lie in the setup of the CollectionViewController in the storyboard. I've only just got in and it's passed midnight so I'm to tired for an explanation now but I will attempt one tomorrow (later today actually). – Upholder Of Truth Dec 26 '17 at 00:08
  • @UpholderOfTruth sounds good - get some sleep :) – zoecarver Dec 26 '17 at 00:33

1 Answers1

1

The Cause: The main cause of the problem is how the CollectionViewController is setup in the storyboard. In summary these are the main issues with it:

  1. The CollectionViewController was added as a UIViewController and then the class changed to CollectionViewController but the problem is that is a subclass of a UICollectionViewController. So there is a miss match between what the storyboard thinks it is and what it actually is. You should have added it as a UICollectionViewController to begin with.
  2. The CollectionViewControllers top view has had it's class changed from UIView to UICollectionView which I assume was to match how the UICollectionViewController is setup. So again there is a miss match here meaning you can't see any of the correct properties in the Interface Builder.
  3. There is then an additional UICollectionView added as a sub view of the main CollectionViewController main view. This has its data source and delegate linked into the CollectionViewController class and is the one that is actually being displayed. It's all setup correctly with a prototype cell. However it's not linked into the class as an IBOutlet so you can't reference it.

So why is this causing the problem you are seeing. In the CollectionViewController when you refer to self.collectionView you are referring to the top level one which is not the one that is displaying the cells. That's not the one displaying the cells and in fact has no displayed cells so when you ask for the cell at a particular point it will always return nil and hence you get a row value of zero. If you were able to get access to the UICollectionView actually displaying the cells you could get the correct value.

Other than that there will be other issues that you haven't come across yet.

The Solution: There are basically two main solutions to this problem...

  1. Remove the CollectionViewController from the storyboard and add it again as a UICollectionViewController. This of course is the ideal way to resolve it as it will all be setup correctly however it will require re-creating the entire controller in the storyboard again and is not absolutely necessary as you can do method 2...
  2. You can modify your storyboard and setup to correctly reflect the setup you have and get it working.

I have tried method 2 and this is what I had to do to get it working correctly:

Change the CollectionViewController from subclassing UICollectionViewController to subclassing UIViewController as it will just become a holder for the UICollectionView. You also need to make it support UICollectionViewDataSource and UICollectionViewDelegate directly as the UICollectionViewController already does this but the UIViewController doesn't. So change this line in CollectionViewController.m:

@interface CollectionViewController : UICollectionViewController

to this:

@interface CollectionViewController : UIViewController <UICollectionViewDelegate, UICollectionViewDataSource>

Next in the storyboard change the top level view of the CollectionViewController back to a UIView (i.e. delete the UICollectionView in the class property). It's now just a holder for the real UICollectionView.

Next link the remaining UICollectionView that is setup in the storyboard to an IBOutlet in CollectionViewController.h called 'collectionView' so that all the references to self.collectionView are now referring to the correct thing.

One extra thing I had to do but I'm not sure why is change the cell identifier for the UITableViewController and UICollectionViewController so that they are not both 'Cell'. I just used 'TableCell' and 'CollectionCell'. If you don't do this they both get confused for some reason.

(I think that is all I did but if not I'm sure you will be able to handle any other issues)

Once all that has been done then the self.collectionView will be referring to the correct thing and you will get the correct index path in the - (UIViewController *) previewingContext:(id <UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location method.

Bonus Round: Now some extra bonus comments. You appear to also have the same kind of issue with the TableViewController although it doesn't appear to be causing any issues at the moment. You may want to fix it though.

When I first ran the project I could not see anyway to add anything to the table because the text field and 'add' button were missing. This turned out to be because I was using an iPhone 8 simulator not an iPhone X simulator and once I switched everything was ok and I could see the text field and 'add' button. What this means is your interface is not adapting to the different device sizes correctly (at all really) and you should really address that.

Phew that ended up longer than I thought but hopefully will clear up the problem. Also as I had access to the git repository I could clone it and make my changes. I obviously haven't committed them as it's your repository but if you have any trouble understanding what I have done to get it to work I can commit them ether into your main branch or as a new branch.

Upholder Of Truth
  • 4,643
  • 2
  • 13
  • 23
  • Thank you so much for that answer! I finally got the force touch working using the first solution you provided. The only issue is now I cannot set any of the text labels, not sure what that is about - any ideas? Thanks again for the amazing answer. Edit: it looks like I actually cannot edit any of the custom properties of the `CollectionViewCell`. – zoecarver Dec 26 '17 at 20:14
  • I have updated the code in the repo if you want to take a look at it. – zoecarver Dec 26 '17 at 20:24
  • I've pulled out the latest version. Where are you trying to update the CollectionViewCell? – Upholder Of Truth Dec 26 '17 at 20:42
  • its in the `CollectionViewController`, line 125. here: https://github.com/pudility/quick-things/blob/master/quickthings/src/components/CollectionViewController.m#L110-L142 - or more specifically here: https://github.com/pudility/quick-things/blob/master/quickthings/src/components/CollectionViewController.m#L129 thanks again for the help! – zoecarver Dec 26 '17 at 20:50
  • I did a pull but FetchSettings.h is not found. – Upholder Of Truth Dec 26 '17 at 20:56
  • Sorry for the delayed responce... it looks like its right here: https://github.com/pudility/quick-things/blob/master/quickthings/src/actions/FetchSettings.h. Can you see it under actions in the xcode project? – zoecarver Dec 26 '17 at 21:33
  • Ignore that as it's an issue with Xcode which builds the project successfully and then says there is that error which in fact there isn't – Upholder Of Truth Dec 26 '17 at 21:38
  • I don't think thats the issue - What I am talking about is that when you build it and run it - the text is not set in the collection view for some reason. Like this: https://imgur.com/KYwKwpH – zoecarver Dec 26 '17 at 21:50
  • No that was my issue I am looking into your problem now – Upholder Of Truth Dec 26 '17 at 21:52
  • That was quite a subtle one. It's because you have added this `[self.collectionView registerClass:[CollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier];` in your `viewDidLoad` method. that registers the class manually and breaks the link with the storyboard. You don't need to do that at all so can just remove that line completely. It then uses the storyboard version and the labels appear. – Upholder Of Truth Dec 26 '17 at 22:03
  • Perfect! Your the best! Thanks again for the help! – zoecarver Dec 26 '17 at 22:04
  • No problem. The project has certainly improved a lot between updates so good work there. – Upholder Of Truth Dec 26 '17 at 22:06