Search code examples
objective-ciosuiactionsheetuicollectionview

UIActionSheet only showing once


I have the following code which produces a UICollectionView. When you longpress on a UICollectionViewCell, a UIActionSheet appears.

This works, but only once. If you dismiss the UIActionSheet and longpress the same cell again, nothing happens.

Any ideas what I am doing wrong?

#import "ProjectsListViewController.h"
#import <QuartzCore/QuartzCore.h>

@interface ProjectsListViewController ()

@end

@implementation ProjectsListViewController

@synthesize appDelegate;

- (void)viewDidLoad
{
    [super viewDidLoad];

    appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

    // CREATE THE COLLECTION VIEW
    UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];

    [self setCollectionView:[[UICollectionView alloc] initWithFrame:CGRectMake(20, 54, [[self view] bounds].size.width - 40, [[self view] bounds].size.height) collectionViewLayout:flowLayout]];
    [[self collectionView] setDataSource:self];
    [[self collectionView] setDelegate:self];
    [self.view addSubview:self.collectionView];
    [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"Cell"];
    [[self collectionView] setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
}

- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section
{
    return [[[appDelegate userSettingsDictionary] objectForKey:@"Projects"] count];
}

- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView 
{
    return 1;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{    
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];

    // CREATE A BACKGROUND VIEW FOR THE FOLDER IMAGE
    UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"folder.png"]];
    UIView *background = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 122, 89)];
    [background setBackgroundColor:[UIColor colorWithPatternImage:image]];
    [cell addSubview:background];

    // SET THE CELL TEXT
    UILabel *cellLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 95, 130, 100)];
    [cellLabel setText:[[[[[appDelegate userSettingsDictionary] objectForKey:@"Projects"] objectAtIndex:[indexPath row]] objectForKey:@"Project Name"] uppercaseString]];

    // LISTEN FOR A LONG PRESS ON EACH FOLDER
    UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
    [cell addGestureRecognizer:longPress];

    [cell addSubview:cellLabel];
    return cell;
}

// PRESENT AN ACTION SHEET WHEN A FOLDER HAS RECEIVED A LONG PRESS EVENT
- (void)handleLongPress:(UILongPressGestureRecognizer *)recognizer
{
    if ( [recognizer state] == UIGestureRecognizerStateBegan )
    {
        UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"Select an action" delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Delete" otherButtonTitles:@"Edit", nil];

        [actionSheet addGestureRecognizer:recognizer];

        // SET THE SELECTED FOLDER'S ROW NUMBER AS THE ACTIONSHEET TAG.  JUST A WAY OF LETTING THE DELETE METHOD KNOW WHICH FOLDER TO DELETE
        [actionSheet showInView:self.view];
    } 
}

// GET THE SIZE OF THE FOLDER IMAGE AND SET EACH COLLECTION VIEW ITEM SIZE TO FIT
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"folder.png"]];
    return CGSizeMake(image.size.width, image.size.height + 50);
}


- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    return UIEdgeInsetsMake(10, 10, 90, 10);
}

@end

Thanks


Solution

  • I actually tried something similar a while ago, and figured out that almost the whole approach was wrong.

    To start with: The way you set up your cells isn't good. Because cells are reusable, but now you add the subviews each time the collection view asks for a specific cell. You should subclass UICollectionViewCell and add subviews in the initWithCoder: method.

    Then just create a property on the subclass for the text field. Then in the collectionView:cellForItemAtIndexPath: you just set the text to the labels text property.

    Now let's fix the gesture recognizer. You shouldn't set a gesture recognizer for each UICollectionViewCell, but just one global one. In viewDidLoad: you should add:

    UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
    [self.collectionView addGestureRecognizer:longPress];
    

    Then you should change the handleLongPress: to something like this:

    - (void)handleLongPress:(UILongPressGestureRecognizer *)gesture {
        if (gesture.state == UIGestureRecognizerStateBegan) {
            NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:[gesture locationInView:self.collectionView]];
    
            if (indexPath != nil) {
                self.currentIndexPath = indexPath;
    
                UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"Select an action" delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Delete" otherButtonTitles:@"Edit", nil];
    
                UICollectionViewCell *itemCell = [self.collectionView cellForItemAtIndexPath:indexPath];
                [action showFromRect:CGRectMake(0, 0, itemCell.frame.size.width, itemCell.frame.size.height) inView:itemCell animated:YES];
            }
        }
    }
    

    Note that I didn't add the line for adding the recognizer to the action sheet, I don't get why you should do that. And you should also add a property named currentIndexPath.

    Everything should be set up right at this moment. When you get an response from your action sheet, just use the self.currentIndexPath to identify which item to delete/edit.