Buttons on UITableViewCell not working when in editing mode - ios

I have a UITableView populated with cells that have buttons on them. I want those buttons to work also when in editing mode, but they don't. It seems like the gesture recognizer on UITableViewCell is preventing gesture recognizers on buttons. Does anyone have any suggestions about approaching this problem?
ViewController.m:
- (void)viewDidLoad {
[super viewDidLoad];
self.items = [#[#"one", #"two", #"three", #"four"] mutableCopy];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: #"cellID"
forIndexPath:indexPath];
if (cell == nil) {
cell = [[TableViewCell alloc] init];
}
[cell.button setTitle: self.items[indexPath.row]
forState: UIControlStateNormal];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[self.items removeObjectAtIndex: indexPath.row];
}
}
TableViewCell.h:
#interface TableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UIButton *button;
- (IBAction)buttonTapped:(id)sender;
#end
So, the buttonTapped: is called when a cell isn't in editing mode, but when a cell is in editing mode, the button doesn't work.

Use different tags from each button in the cells. For example,
Inside cellforRowAtIndexPath, specify a tag for a button.
[Button addTarget:self action:#selector(func:event:) forControlEvents:UIControlEventTouchUpInside];
[Button setTag:indexPath.row];
Now call the function and refer the cell using tag.
-(IBAction)func:(id)sender event:(id)event{
UITouch *touch = [[event allTouches] anyObject];
CGPoint Pos = [touch locationInView:self.tableview];
NSIndexPath *indexPath = [self.tableview indexPathForRowAtPoint:Pos];
if(indexPath != nil){
//do operation with indexPath
}
}
Hope it helps...

First of all see some code what you have done !! without proper declaration its difficult to give answer.
Firstly My suggestion is give gesture recognize in UItableview delegate method.
- (void)tableView:(UITableView*)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
// code
}
Sometimes gesture is not working with small mistake in coding.
Secondly if possible ,
Instead of adding the Gesture recognizer to the Cell directly, you can add it to the UItableview in viewDidLoad.
This is the best way to work gesture in UITableview.
As said by Phix in Example,
In the didSwipe-Method you can determine the affected IndexPath and cell as follows:
-(void)didSwipe:(UIGestureRecognizer *)gestureRecognizer {
if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
CGPoint swipeLocation = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *swipedIndexPath = [self.tableView indexPathForRowAtPoint:swipeLocation];
UITableViewCell* swipedCell = [self.tableView cellForRowAtIndexPath:swipedIndexPath];
// ...
}
}
You can set other gesture like as Above.
I hope it will solve your issue.

To do this, you need to subclass the UITableView and make it conform to a UIGestureRecognizerDelegate protocol. In .m file of your UITableView subclass add the following code:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass: [UIButton class]]) {
return NO;
}
return YES;
}

Related

LongPress gesture not called on UITableView

In an iOS App, I have a UITableView (NOT part of a UITableViewController) on which I want to detect long press on custom UITableViewCells with the following method:
- (void)viewDidLoad
{
myTableView.delegate=self;
myTableView.dataSource=self;
UILongPressGestureRecognizer *longTap = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longTapGestureCaptured:)];
longTap.minimumPressDuration=0.5f;
longTap.delegate=self;
[myTableView addGestureRecognizer:longTap];
[super viewDidLoad];
}
-(void)longTapGestureCaptured:(UILongPressGestureRecognizer *)gesture
{
NSLog(#"Long tap"); // never called
}
However the longTapGestureCaptured is never called when I longpress. How can this be resolved ?
I tried your code. it's 100% working for me. But small change in your code is...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Create cell here
UITableViewCell *cell;
cell= (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
//Add gesture to cell here
UILongPressGestureRecognizer *longTap = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longTapGestureCaptured:)];
longTap.minimumPressDuration=1.5f;
longTap.delegate=self;
[cell addGestureRecognizer:longTap];
cell.textLabel.text = #"Name";//Send your data here
return cell;
}
-(void)longTapGestureCaptured:(UILongPressGestureRecognizer *)gesture
{
NSLog(#"Long tap"); // never called
}
You add longPress even for UITableview. But when table have cells, cell of table will over on UITableView, so you can not longPress on TableView. Reslove for you is add longPress even on each Cell of Table. By add code add longPress even for each cell in function cellAtIndex. Good luck.

Swipe to delete cell by only one gesture

I would like to delete cell by one swipe gesture. The problem is that when I slide left delete icon will appear. Of course when I click on delete icon cell will be deleted. I would like to delete cell immediately after swipe gesture. It is supported by ios 9?
More details
When the user slide left to the middle of the cell delete button will appear. When he will continue swiping to the edge of the screen cell will be deleted.
Why don't you have a custom table cell
On the cell add swipe gesture on the content view or any portion,
Delegate its call to the tableviewcontroller with the indexpath
- (void)someDelegateFunctionToDeleteCellAtIndexPath:(NSIndexpath *)indexPath{
[dataSourceArray removeObjectAtIndex:indexPath.row];
NSArray *deleteIndexPaths = #[indexPath];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:deleteIndexPaths withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
}
Use UISwipeGesture on UITableView:
- (void)viewDidLoad
{
[super viewDidLoad];
UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:sel
action:#selector(leftSwipe:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionLeft)];
[self.tableView addGestureRecognizer:recognizer];
}
- (void)leftSwipe:(UISwipeGestureRecognizer *)gestureRecognizer
{
CGPoint location = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
[dataSourceArray removeObjectAtIndex:indexPath.row];
[tableView reloadData];
}
I tried the solution for your question.Very easily I got the solution.
.m
#import "ViewController.h"
#interface ViewController ()
{
NSMutableArray *arrayData;
}
#end
#implementation ViewController
#synthesize tableViewSwipeDelete;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
arrayData = [[NSMutableArray alloc]initWithObjects:#"iOS",#"Android",#"Windows",#"Tablet",#"iPAD", nil];
UISwipeGestureRecognizer *gestureDeleteRow = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(cellSwipe:)];
gestureDeleteRow.direction = UISwipeGestureRecognizerDirectionLeft;
[tableViewSwipeDelete addGestureRecognizer:gestureDeleteRow];
}
-(void)cellSwipe:(UISwipeGestureRecognizer *)gesture
{
CGPoint location = [gesture locationInView:tableViewSwipeDelete];
NSIndexPath *swipedIndexPath = [tableViewSwipeDelete indexPathForRowAtPoint:location];
//Delete Row…
[arrayData removeObjectAtIndex:swipedIndexPath.row];
[tableViewSwipeDelete deleteRowsAtIndexPaths:[NSArray arrayWithObjects:swipedIndexPath, nil] withRowAnimation:UITableViewRowAnimationLeft];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return arrayData.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *strCell = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:strCell];
if(cell==nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strCell];
}
cell.textLabel.text = arrayData[indexPath.row];
return cell;
}
#end
Above my answer works perfectly.

UITableView: How can I change UIView status in CUSTOMIZED CELL with LONGPRESS?

I'm a beginner to making iPhone app with Xcode6. (and excuse me non a native English speaker...)
setting up UITableView with customized cells (as another class, i.e. MyCustomCell)
I would like to show/hide a component (UIView) in customized cell class, when a cell in UITableView has a longpress (longTap) but stacked.
I could not know how to control (recognise) the target component on the same cell in customized cell class with indexPath (or something) some part of programs are as follows,
MyCustomCell.h
#interface MyCustomCell : UITableViewCell
#property (weak,nonatomic) IBOutlet UIView *customPanel;
UIViewController.m
#import “MyCustomCell.h"
********************************
- (void)viewDidLoad {
[super viewDidLoad];
[_tableView registerNib:[UINib nibWithNibName:#“MyCustomCell" bundle:nil] forCellReuseIdentifier:#"cell"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
return cell;
}
-(void)longtapAction:(UILongPressGestureRecognizer *)gestureRecognizer {
CGPoint p = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:p];
if (indexPath == nil){
}else if (gestureRecognizer.state == UIGestureRecognizerStateBegan){
// I would like to change the hidden status of a UIVIEW in the CustomCell like
{self.customcell.custompanel:(indexPath).hidden = YES;}
}
}
Would you please let me know how to go over this trap ?
You need to create and assign a gestureRecognizer in to a cell:cellForRowAtIndexPath
UILongPressGestureRecognizer * recognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longTapAction:)];
recognizer.delegate = self;
[cell addGestureRecognizer:recognizer];
You can add the gesture-recogniser to the UITableView itself and then extract the target UITableViewCell on which the gesture was performed using something like this or this.

How to get value from UITableViewCell

I'm having a problem in getting a value in uitableviewcell.
first of all, i have a label on my cell which I've created a tap gesture on it. What i want to do is on tapping that label, viewUser method will be call and it will get the details of that cell being tapped.
Here is my code:
on cellForRowAtIndexPath:
cell.userNameLabel.text = [[_workflowList objectAtIndex:indexPath.row] userName];
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(viewUser:)];
tapGestureRecognizer.numberOfTapsRequired = 1;
[cell.userNameLabel addGestureRecognizer:tapGestureRecognizer];
cell.userNameLabel.userInteractionEnabled = YES;
Now, when i call my ontap method which is viewUser:
- (IBAction)viewUser:(id)sender {
//this should not be hard coded
//data should come from cell.
//usernamelabel or i will get the index selected
//and get the details in my array
// like this --> [_workflowList objectAtIndex:index]
WorkflowProfileViewController *chkDtl = [[WorkflowProfileViewController alloc]init];
chkDtl.name = #"USER, USER USER"; ;
chkDtl.phoneNo = #"09173210836";
chkDtl.email = #"romelync#sxchange.com";
[self.navigationController pushViewController:chkDtl animated:YES];
}
Please help me on this.
The best option would be to use UITableView delegate method tableView:didSelectRowAtIndexpath: as below:
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
WorkflowProfileViewController *chkDtl = [[WorkflowProfileViewController alloc]init];
chkDtl.name=[[_workflowList objectAtIndex:indexPath.row] userName];
[self.navigationController pushViewController:chkDtl animated:YES];
}
Don't forget to set delegate of your tableView.
UPDATE: Then I think you want to do something like below. In your cellForRowAtaIndexPath: add following:
cell.userNameLabel.tag=indexPath.row;
And in viewUser method:
UITapGestureRecognizer *tap=(UITapGestureRecognizer*)sender;
WorkflowProfileViewController *chkDtl = [[WorkflowProfileViewController alloc]init];
chkDtl.name=[[_workflowList objectAtIndex:tap.view.tag] userName];
[self.navigationController pushViewController:chkDtl animated:YES];
When creating UILable you could put the tag value as row number
lable.tag = indexPath.row
In your method then retrieve label and look for tag value.
Something like below will get the cell you are tapping (replace swipe with tap):
- (void)handleSwipeRight:(UISwipeGestureRecognizer *)gestureRecognizer{
CGPoint location = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *swipedIndexPath = [self.tableView indexPathForRowAtPoint:location];
self.currentSwipedCell = [self.tableView cellForRowAtIndexPath:swipedIndexPath];
}
Havent tested it yet but:
-(void)viewUser:(UITapGestureRecognizer):gestureRecognizer{
CGPoint location = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
self.currentTappedCell = [self.tableView cellForRowAtIndexPath:indexPath];
NSLog(self.currentTappedCell.name); // If you have a custom cell with a name property
}
Definitely you should use the proper delegate methods instead implementing UITapGestureRecognizer on an UITableViewCell. Then you can get the informations you want pretty easily:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *theUserNameYouWantToGet = [_workflowList objectAtIndex:[indexPath row]];
}
EDIT:
If you want that action not to work for the whole cell, you could subclass UITableViewCell, add properties to it and implement your own delegate protocol to that cell:
#protocol JWTableViewCellDelegate;
#interface JWTableViewCell : UITableViewCell
#property (nonatomic, retain) NSString *username;
#property (nonatomic, assign) id<JWTableViewCellDelegate>delegate;
#end
#protocol JWTableViewCell <NSObject>
- (void)tableViewCellDidClickUsername:(JWTableViewCell *)cell;
#end
#implementation JWTableViewCell
- (void)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
[self setupView];
}
return self;
}
// if you use a prototyping NIB
- (void)awakeFromNib {
[self setupView];
}
- (void)setupView {
// add gesture recognizer
}
- (void)handleGesture {
if ([_delegate respondsToSelector:#selector(tableViewCellDidClickUsername:)]) {
[_delegate tableViewCellDidClickUsername:self];
}
}
Then use this in your viewController:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
JWTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"reuseID" forIndexPath:indexpath];
[cell setUsername:#"Paul"];
[cell setDelegate:self];
}
- (void)tableViewCellDidClickUsername:(JWTableViewCell *)cell {
NSString *theUserNameYouWantToGet = [cell username];
  }

iOS - indexPathForRowAtPoint don't return correct indexPath with different cell height

I have UITableView that contains many cell. User can expand cell to see more content in this cell by push the expand button in this cell (only 1 cell can expand at time):
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(selectedRowIndex == indexPath.row) return 205;
else return 60;
}
In the storyboard, I drag UILongPressGesture into cell button and named it longPress (cell is custom, it has 2 buttons in it, 1 need to recognize LongPressGesture, the other expand cell height):
#property (retain, nonatomic) IBOutlet UILongPressGestureRecognizer *longPress;
And in the viewDidLoad:
- (void)viewDidLoad
{
[longPress addTarget:self action:#selector(handleLongPress:)];
}
It's work perfectly, however when I use following code to recognize cell indexPath, it's wrong when one cell is expanded:
- (void)handleLongPress:(UILongPressGestureRecognizer*)sender {
// Get index path
slidePickerPoint = [sender locationInView:self.tableView];
NSIndexPath *indexPath= [self.tableView indexPathForRowAtPoint:slidePickerPoint];
// It's wrong when 1 cell is expand and the cell's button I hold is below the expand button
}
Can anyone please show me how to get correct indexPath when there're different cell height?
Thank in advance
One way to do it would be to add a UILongPressGestureRecognizer to each UITableViewCell (that all use the same selector), then when the selector is called you can get the cell via sender.view. Perhaps not the most memory efficient, but if the single gesture recognizer won't return the right row in certain situations, this way should work.
Something like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(handleLongPress:)];
[longPress setMinimumPressDuration:2.0];
[cell addGestureRecognizer:longPress];
[longPress release];
return cell;
}
then
- (void)handleLongPress:(UILongPressGestureRecognizer*)sender {
UITableViewCell *selectedCell = sender.view;
}
First add the long press gesture recognizer to the table view:
UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(handleLongPress:)];
lpgr.minimumPressDuration = 2.0; //seconds
lpgr.delegate = self;
[self.myTableView addGestureRecognizer:lpgr];
[lpgr release];
Then in the gesture handler:
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
CGPoint p = [gestureRecognizer locationInView:self.myTableView];
NSIndexPath *indexPath = [self.myTableView indexPathForRowAtPoint:p];
if (indexPath == nil)
NSLog(#"long press on table view but not on a row");
else
NSLog(#"long press on table view at row %d", indexPath.row);
}
}
You have to be careful with this so that it doesn't interfere with the user's normal tapping of the cell and also note that handleLongPress may fire multiple times before user lifts their finger.
Thanks...!

Resources