-1

In my project I am using UICollectionView to display data. Data showing perfectly into UICollectionViewCells but I am also using "Edit" and "Delete" buttons in cells to edit or delete the data.

The problem occurs when I try to edit any cell and press the "edit" button. It only works for the first 3 cells. When I click on the fourth cell's edit button it displays the result of first cell on the edit page, for fifth cell it display result of second row and for 6th cell it display content of third row then for 7th row it again display result of first cell and this process continues till the end of the cells.

Edit Function

    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
    {

        static NSString *identifier = @"cellIdentifier";
        UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];

       editbtn = (UIButton *)[cell.contentView viewWithTag:206];
        editbtn.tag = indexPath.row;
        [editbtn addTarget:self action:@selector(editprocedure:) forControlEvents:UIControlEventTouchUpInside];
        [editbtn setTintColor:[UIColor blackColor]];

        deletebtn = (UIButton *)[cell.contentView viewWithTag:207];
        [deletebtn addTarget:self action:@selector(deleteprocedure:) forControlEvents:UIControlEventTouchUpInside];
        [deletebtn setTintColor:[UIColor blackColor]];
        deletebtn.tag = indexPath.row;

        return cell;
    }

i am also sharing screenshot what it looklike on simulator

enter image description here

Here is the code for edit function

-(IBAction)editprocedure:(UIButton*)sender
{
    UIButton *btnTapped = (UIButton *)sender;
    self.strdiagid = btnTapped.accessibilityIdentifier;
    NSLog(@"str ID : %@",self.strdiagid);

    self.strdiagid = [CompletephyDic objectForKey:@"id"];
    UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];
    EditProcedureVC *vch = [mainStoryboard instantiateViewControllerWithIdentifier:@"EditProcedureVC"];

    self.strdiagid = [CompletephyDic objectForKey:@"id"];
    NSString * a = self.strdiagid;
    NSLog(@"id...%@",a);

    vch.stridd = a; //stridd is the id of the procedure which is transferred to other view
    vch.infoDictionary = [dataArray objectAtIndex:sender.tag];

    [self presentViewController:vch animated:NO completion:nil];
}
  • for forth cell the button action is call or not ? if not please check the cell size in collectionview. – Ilesh P Mar 04 '16 at 05:39
  • in cells data is coming from api and it is about 15 cells in collectionview. edit button is working well for first 3 cells by the above code but for fourth cell it display the content of first cell –  Mar 04 '16 at 05:41
  • It is due to the collectionView's behaviour of reusing the cells, I might help you if you could share code for editprocedure, deleteprocedure. – Bharat Modi Mar 04 '16 at 06:37
  • please check it again i updated my question also please upvote que so that i can add screenshots and use more functions of this site –  Mar 04 '16 at 06:58
  • You are making mistake at this line vch.infoDictionary = [dataArray objectAtIndex:sender.tag]; Your buttons tag is 206 and 207, due to this you are getting wrong data. – Bharat Modi Mar 04 '16 at 07:56
  • @BharatModi That line is only used to send the dictionary of the selected cell to other view(edit view) if i comment that line the problem remains same –  Mar 04 '16 at 09:19
  • I'm confused now, if you comment that line then which data you are showing on EditScreen? Also please explain this line self.strdiagid = [CompletephyDic objectForKey:@"id"]; is it array of dictionaries? – Bharat Modi Mar 04 '16 at 09:24
  • this is my second effort to get correct result. i also have another api for edit screen which require only id of the selected cell which i send as 'stridd' –  Mar 04 '16 at 09:28
  • What structure does this dictionary has? – Bharat Modi Mar 04 '16 at 09:47

4 Answers4

0

Try this :

 - (void)prepareForReuse {
        [super prepareForReuse];
        //Reset your components to nil here.
    }
Pulkit Sharma
  • 545
  • 1
  • 6
  • 19
  • where to call this function? this gives an error "no visible @interface for.......declares the selector 'PrepareForReuse'" –  Mar 04 '16 at 07:11
0

Subclass UICollectionViewCell and set your collectionViewCell's custom class to this subclassed class on storyboard. Make outlet of EditButton and DeleteButton.

Replace your button's tag with indexPath row or section and access it as the following :-

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    CustomCollectionViewCells *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cvCells" forIndexPath:indexPath];
    [cell.editButton setTag:indexPath.row];
    [cell.button addTarget:self action:@selector(clicked:) forControlEvents:UIControlEventTouchUpInside];
    }

- (IBAction)clicked:(id)sender {

    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[sender tag] inSection:0];

    CustomCollectionViewCell *cell = (CustomCollectionViewCell *) [self.collectionview cellForItemAtIndexPath:indexPath];
          //Your desired code for the specific cell
    }

Hope it helps. Please let me know, if you have any queries.

Bharat Modi
  • 4,158
  • 2
  • 16
  • 27
0

Try this

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:YES];

    [self setAutomaticallyAdjustsScrollViewInsets:NO];
}
Bhavin Ramani
  • 3,221
  • 5
  • 30
  • 41
Nisha Gupta
  • 275
  • 1
  • 14
  • please upvote my question so that i will b able to ask new question –  Mar 08 '16 at 05:42
0

Unfortunately the selected answer didn't work for me. Here is a write-up of what did:

I spent hours scouring the web for a solution to my UIButton's inside UICollectionView's not working. Driving me nuts until I finally found a solution that works for me. And I believe it's also the proper way to go: hacking the hit tests. It's a solution that can go a lot deeper (pun intended) than fixing the UICollectionView Button issues as well, as it can help you get the click event to any button buried under other views that are blocking your events from getting through:

UIButton in cell in collection view not receiving touch up inside event

Since that SO answer was in Objective C, I followed the clues from there to find a swift solution:

http://khanlou.com/2018/09/hacking-hit-tests/

--

When I would disable user interaction on the cell, or any other variety of answers I tried, nothing worked.

The beauty of the solution I posted above is that you can leave your addTarget's and selector functions how you are used to doing them since they were most likey never the problem. You need only override one function to help the touch event make it to its destination.

Why the solution works:

For the first few hours I figured the gesture wasn't being registered properly with my addTarget calls. It turns out the targets were registering fine. The touch events were simply never reaching my buttons.

The reality seems to be from any number of SO posts and articles I read, that UICollectionView Cells were meant to house one action, not multiple for a variety of reasons. So you were only supposed to be using the built in selection actions. With that in mind, I believe the proper way around this limitation is not to hack UICollectionView to disable certain aspects of scrolling or user interaction. UICollectionView is only doing its job. The proper way is to hack the hit tests to intercept the tap before it gets to UICollectionView and figure out which items they were tapping on. Then you simply send a touch event to the button they were tapping on, and let your normal stuff do the work.


My final solution (from the khanlou.com article) is to put my addTarget declaration and my selector function wherever I like (in the cell class or the cellForItemAt override), and in the cell class overriding the hitTest function.

In my cell class I have:

@objc func didTapMyButton(sender:UIButton!) {
    print("Tapped it!")
}

and

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

    guard isUserInteractionEnabled else { return nil }

    guard !isHidden else { return nil }

    guard alpha >= 0.01 else { return nil }

    guard self.point(inside: point, with: event) else { return nil }


    // add one of these blocks for each button in our collection view cell we want to actually work
    if self.myButton.point(inside: convert(point, to: myButton), with: event) {
        return self.myButton
    }

    return super.hitTest(point, with: event)
}

And in my cell class init I have:

self.myButton.addTarget(self, action: #selector(didTapMyButton), for: .touchUpInside)
xxxx
  • 241
  • 3
  • 5