I am attempting the following:
Within each cell I have date-from and date-to UITextField. When the user presses either TextField an InputView of the DatePicker appears with a Done button to complete.
My challenge is I only want the user to be able to select either of the TextFields inside the selected cell and no other. The user must press Done on InputView when they have finished, so the app can validate and reload TableView if necessary.
I have code that manages normal cell selection well when the 'keyboard' is shown, but cannot manage the UITextField behavior as I would like.
I share some code in the hope someone can help me:
- (void)keyboardWillShow:(NSNotification*)aNotification {
self.TableViewDiary.allowsSelection = NO;
}
- (void)keyboardWillBeHidden:(NSNotification*)aNotification {
self.TableViewDiary.allowsSelection = YES;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ActivityDiaryCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ActivityDiaryCellId"];
cell.activity = [self.activitycollection objectAtIndex:indexPath.row];
cell.LabelName.text = cell.activity.name;
cell.TextFieldStartDt.text = [self FormatPrettyTime :cell.activity.startdt];
cell.TextFieldEndDt.text = [self FormatPrettyTime :cell.activity.enddt];
cell.datePickerStart.date = cell.activity.startdt;
cell.datePickerEnd.date = cell.activity.enddt;
cell.tag = indexPath.row;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
ActivityDiaryCell
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
self.datePickerStart = [[UIDatePicker alloc] init];
self.datePickerStart.datePickerMode = UIDatePickerModeDateAndTime;
//self.datePickerStart.date = self.activity.startdt;
[self.datePickerStart addTarget:self action:#selector(datePickerStartValueChanged:) forControlEvents:UIControlEventValueChanged]; // method to respond to changes in the picker value
self.datePickerEnd = [[UIDatePicker alloc] init];
self.datePickerEnd.datePickerMode = UIDatePickerModeDateAndTime;
//self.datePickerEnd.date = self.activity.enddt;
[self.datePickerEnd addTarget:self action:#selector(datePickerEndValueChanged:) forControlEvents:UIControlEventValueChanged]; // method to respond to changes in the picker value
self.datePickerToolbar=[[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, self.bounds.size.width, 44)];
[self.datePickerToolbar setTintColor:[UIColor grayColor]];
UIBarButtonItem *doneBtn=[[UIBarButtonItem alloc]initWithTitle:#"Done" style:UIBarButtonItemStylePlain target:self action:#selector(dismissPicker:)];
UIBarButtonItem *space=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
[self.datePickerToolbar setItems:[NSArray arrayWithObjects:space,doneBtn, nil]];
self.TextFieldStartDt.delegate = self;
self.TextFieldStartDt.inputView = self.datePickerStart;
self.TextFieldStartDt.inputAccessoryView = self.datePickerToolbar;
self.TextFieldEndDt.delegate = self;
self.TextFieldEndDt.inputView = self.datePickerEnd;
self.TextFieldEndDt.inputAccessoryView = self.datePickerToolbar;
}
Keyboard is showing because a user has tapped a text field, not because they selected a cell. That's why allowsSelection doesn't affect it.
Move the UITextFieldDelegate handling to your UITableViewController. Then you can easily decide whether to show a date picker or not:
if date picker is hidden, show it and remember a cell which textfield is on
if date picker is already visible, check whether text field belongs to the same cell and either update date picker or do nothing (by overriding textFieldShouldBeginEditing(_:) and returning false)
I moved the UITextFieldDelegate up to the TableViewController and included following code there:
-(bool) textFieldShouldBeginEditing:(UITextField *)textField {
if (self.TableViewDiary.allowsSelection) {
return true;
} else {
CGPoint buttonPosition = [textField convertPoint:CGPointZero toView:self.TableViewDiary];
NSIndexPath *indexPath = [self.TableViewDiary indexPathForRowAtPoint:buttonPosition];
ActivityDiaryCell *cell = [self.TableViewDiary cellForRowAtIndexPath:indexPath];
if ([cell.TextFieldStartDt isFirstResponder] || [cell.TextFieldEndDt isFirstResponder]) {
return true;
}
}
return false;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
CGPoint buttonPosition = [textField convertPoint:CGPointZero toView:self.TableViewDiary];
NSIndexPath *indexPath = [self.TableViewDiary indexPathForRowAtPoint:buttonPosition];
ActivityDiaryCell *cell = [self.TableViewDiary cellForRowAtIndexPath:indexPath];
[cell setSelected:YES animated:NO];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
CGPoint buttonPosition = [textField convertPoint:CGPointZero toView:self.TableViewDiary];
NSIndexPath *indexPath = [self.TableViewDiary indexPathForRowAtPoint:buttonPosition];
ActivityDiaryCell *cell = [self.TableViewDiary cellForRowAtIndexPath:indexPath];
[cell setSelected:NO animated:YES];
}
Related
I am using ABMenuTableViewCell tableview controller in my application. I want to call didSelectRowAtIndexPath when i swipe a UITableViewCell.
Right now didSelectRowAtIndexPath only execute when I tap on a cell, I want to call it even when I swipe it. here is my didSelectRowAtIndexPath and cellforRowAtIndexPath methods code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UILabel *likes;
UILabel *downloads;
static NSString *CellIdentifier = #"Cell";
ABMenuTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[ABMenuTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"acc_arrow_back.png"]];
arrow.frame = CGRectMake(300, 50, 5, 12);
arrow.image = [arrow.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[arrow setTintColor:[UIColor colorWithRed:(191/255.0) green:(2/255.0) blue:(6/255.0) alpha:1]];
[cell.contentView addSubview:arrow];
UIImageView *likes_img = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"social.png"]];
likes_img.frame = CGRectMake(15, 80, 15, 15);
likes_img.image = [likes_img.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[likes_img setTintColor:[UIColor colorWithRed:(191/255.0) green:(2/255.0) blue:(6/255.0) alpha:1]];
[cell.contentView addSubview:likes_img];
likes =[[UILabel alloc]initWithFrame:CGRectMake(33, 78, 80, 20)];
likes.tag = 1001; // set a tag for this View so you can get at it later
likes.textColor=[UIColor darkGrayColor];
likes.font=[UIFont fontWithName:#"Helvetica" size:10.0f];
likes.text=[[rssOutputData objectAtIndex:indexPath.row]xmllikes];
[cell.contentView addSubview:likes];
cell.detailTextLabel.textColor = [UIColor darkGrayColor];
UIImageView *downloads_img = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"download.png"]];
downloads_img.frame = CGRectMake(55, 79, 15, 15);
downloads_img.image = [downloads_img.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[downloads_img setTintColor:[UIColor colorWithRed:(191/255.0) green:(2/255.0) blue:(6/255.0) alpha:1]];
[cell.contentView addSubview:downloads_img];
downloads =[[UILabel alloc]initWithFrame:CGRectMake(73, 78, 80, 20)];
downloads.tag = 1002; // set a tag for this View so you can get at it later
downloads.textColor=[UIColor darkGrayColor];
downloads.font=[UIFont fontWithName:#"Helvetica" size:10.0f];
downloads.text=[[rssOutputData objectAtIndex:indexPath.row]xmldownloads];
[cell.contentView addSubview:downloads];
cell.detailTextLabel.textColor = [UIColor darkGrayColor];
}
else
{
// use viewWithTag to find lblNombre in the re-usable cell.contentView
likes = (UILabel *)[cell.contentView viewWithTag:1001];
downloads = (UILabel *)[cell.contentView viewWithTag:1002];
}
cell.textLabel.text = [[rssOutputData objectAtIndex:indexPath.row]xmlsinger];
cell.detailTextLabel.text = [[rssOutputData objectAtIndex:indexPath.row]xmltitle];
// custom menu view
NSString *nibName = #"ABCellMailStyleMenuView";
ABCellMenuView *menuView = [ABCellMenuView initWithNib:nibName bundle:nil];
menuView.delegate = self;
menuView.indexPath = indexPath;
cell.rightMenuView = menuView;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
And these are the methods in cell class
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer and
- (void)swipeGesture:(UIPanGestureRecognizer *)gesture
here is when i swipe
You can modified swipeGesture method will following code. it will show UITableViewCell as selected once you perform swipe operation.
- (void)swipeGesture:(UIPanGestureRecognizer *)gesture {
if (gesture.state == UIGestureRecognizerStateBegan) {
NSInteger direction;
// find swipe direction
CGPoint velocity = [gesture velocityInView:self];
if (velocity.x > 0) {
// towards right - hide menu view
direction = ABMenuUpdateHideAction;
}
else {
// towards left - show menu view
direction = ABMenuUpdateShowAction;
}
UITableView* tableView = (UITableView*)self.superview.superview;
CGPoint swipeLocation = [gesture locationInView:tableView];
NSIndexPath *swipedIndexPath = [tableView indexPathForRowAtPoint:swipeLocation];
[tableView selectRowAtIndexPath:swipedIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
[self updateMenuView:direction animated:YES];
}
}
Hope this help you.
As you are trying to achieve behaviour not supported by ABMenuTableViewCell, you will need to edit it's source:
Add _tapGesture and _menuVisible instance variables:
#implementation ABMenuTableViewCell {
CGRect _rightMenuViewInitialFrame;
UIPanGestureRecognizer *_swipeGesture;
UITapGestureRecognizer *_tapGesture;
BOOL _menuVisible;
}
Implement -tapGesture: method:
- (void) tapGesture:(UITapGestureRecognizer*)gesture {
if (_menuVisible)
[self updateMenuView:ABMenuUpdateHideAction animated:YES];
else
[self updateMenuView:ABMenuUpdateShowAction animated:YES];
}
Add UITapGestureRecognizer inside -commonInit method:
- (void) commonInit {
_swipeGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(swipeGesture:)];
_swipeGesture.delegate = self;
[self addGestureRecognizer:_swipeGesture];
_tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGesture:)];
_tapGesture.delegate = self;
[self addGestureRecognizer:_tapGesture];
}
Update _menuVisible inside -updateMenuView:animated::
- (void)updateMenuView:(ABMenuUpdateAction)action animated:(BOOL)animated {
...
switch (action) {
case ABMenuUpdateShowAction:
menuNewFrame = CGRectMake(CGRectGetWidth(self.contentView.frame) - initialWidth, .0, initialWidth, CGRectGetHeight(self.contentView.frame));
_menuVisible = YES;
break;
case ABMenuUpdateHideAction:
menuNewFrame = CGRectMake(CGRectGetWidth(self.contentView.frame), .0, .0, CGRectGetHeight(self.contentView.frame));
_menuVisible = NO;
break;
default:
break;
}
...
}
You won't be able to select cells, but as I understand it, you don't want to.
If you want the method to be called when swiping the cell, you should be using a UISwipeGestureRecognizer and not a UIPanGestureRecognizer.
In your viewDidLoad:, set up the gesture recognizer.
// Create a left swipe gesture recognizer
UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeLeft:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionLeft)];
// Add it to the table view
[self.tableView addGestureRecognizer:recognizer];
Handle the swipe.
- (void)handleSwipeLeft:(UISwipeGestureRecognizer *)gestureRecognizer
{
// Get location of the swipe
CGPoint location = [gestureRecognizer locationInView:self.tableView];
//Get the corresponding index path within the table view
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
// Check if index path is valid
if (indexPath)
{
// Select the cell at the indexPath
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
}
That should call the tableView: didSelectRowAtIndexPath: method.
Wondering how can I get all items of each cell in UITableView. My problem is that I want to hide 2 buttons in cell when third is selected.
When I press on button 1, button 2 and 3 must be hidden. What I tried to do for that (in cellForRowAtIndexPath) :
AVMMovieButton *settings = (AVMMovieButton *)[cell viewWithTag:228];
[settings addTarget:self action:#selector(selectSettings:) forControlEvents:UIControlEventTouchUpInside];
settings.tag = indexPath.row;
AVMMovieButton *playButton = (AVMMovieButton *)[cell viewWithTag:134];
[playButton setStore:oneItem];
[playButton addTarget:self action:#selector(playMovie:) forControlEvents:UIControlEventTouchUpInside];
playButton.tag = indexPath.row;
AVMMovieButton *down = (AVMMovieButton *)[cell viewWithTag:282];
AVMMovieButton *del = (AVMMovieButton *)[cell viewWithTag:161];
[settings setSelected:!settings.isSelected];
if (settings.isSelected)
{
NSLog(#"SELECTED!");
down.hidden = YES;
del.hidden = YES;
downLabel.hidden = YES;
delLabel.hidden = YES;
// [self performSelector:#selector(playButtonShow) withObject:nil afterDelay:0.3];
playButton.hidden = NO;
}
else
{
NSLog(#"UNSELECTED!");
playButton.hidden = YES;
down.hidden = NO;
del.hidden = NO;
downLabel.hidden = NO;
delLabel.hidden = NO;
NSLog(#"play button %d",playButton.hidden);
}
and then I added method for selecting my "settings" button:
-(void)selectSettings:(AVMMovieButton *)sender
{
[sender setSelected:!sender.isSelected];
NSLog(#"you just select button");
}
but it doesn't work!
Actually NSLog(#"you just select button"); works, but buttons never hides.
What should I do to get my buttons and hide them?
SOLVED:
All I needed to do was to create custom UITableViewCell class and then access my cell as Jay Gajjar and Akhilrajtr said. After I just used my method for select/deselect my button.
What I've got:
-(void)selectSettings:(AVMMovieButton *)sender
{
AVMMovieButton *settings = (AVMMovieButton *)sender;
CGPoint pointInTable = [settings convertPoint:settings.bounds.origin toView:readyTable];
NSIndexPath *indexPath = [readyTable indexPathForRowAtPoint:pointInTable];
AVMMovieCell *cell=(AVMMovieCell *)[readyTable cellForRowAtIndexPath:indexPath];
if (cell.settingsButton.isSelected)
{
NSLog(#"SELECTED!");
cell.downloadButton.hidden = YES;
cell.deleteButton.hidden = YES;
cell.downLabel.hidden = YES;
cell.delLabel.hidden = YES;
cell.playButton.hidden = NO;
}
else
{
NSLog(#"UNSELECTED!");
cell.playButton.hidden = YES;
cell.downloadButton.hidden = NO;
cell.deleteButton.hidden = NO;
cell.downLabel.hidden = NO;
cell.delLabel.hidden = NO;
NSLog(#"play button %d",cell.playButton.hidden);
}
[settings setSelected:!settings.isSelected];
}
Hope this can be helpful for somebody else!
Try this,
-(void)selectSettings:(AVMMovieButton *)sender{
[sender setSelected:!sender.isSelected];
CGPoint pointInTable = [sender convertPoint:sender.bounds.origin toView:_tableView];
NSIndexPath *indexPath = [_tableView indexPathForRowAtPoint:pointInTable];
[_tableView beginUpdates];
[_tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
[_tableView endUpdates];
NSLog(#"you just select button");
}
cellForRowAtIndexPath is called when Table get reloaded. In your case, what you have to do is:
- (void)button3Method:(id)sender
{
// Begin UITableView Update
[self.tableView beginUpdates];
NSIndexPath *indexPath = // Get cell indexpath for the selected row.
// Logic for getting the UITableViewCell on which you want hide two buttons.
// Logic for hiding those two buttons
// Below line performs reloading of particular UITableViewCell.
[self.tableView reloadRowsAtIndexPaths:#[indexPathOfYourCell] withRowAnimation:UITableViewRowAnimationNone];
// End UITaleView Update
[self.tableView endUpdates];
}
Let me know, if this works for you. Good luck.
In cellForRowAtIndexPath:
[cell. settings addTarget:self action:#selector(selectSettings:) forControlEvents:UIControlEventTouchUpInside];
cell. settings.tag=600+indexPath.row;
In button IBAction:
-(void) selectSettings:(id) sender{
UIButton *btn=(UIButton *)sender;
cellMoreButtonIndex=btn.tag;
YOURCELL *cell=(YOURCELL *)[self.contentTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:btn.tag-600 inSection:0]];
[settings setSelected:!settings.isSelected];
if (settings.isSelected) {
NSLog(#"SELECTED!");
down.hidden = YES;
del.hidden = YES;
downLabel.hidden = YES;
delLabel.hidden = YES;
// [self performSelector:#selector(playButtonShow) withObject:nil afterDelay:0.3];
playButton.hidden = NO;
}else {
NSLog(#"UNSELECTED!");
playButton.hidden = YES;
down.hidden = NO;
del.hidden = NO;
downLabel.hidden = NO;
delLabel.hidden = NO;
NSLog(#"play button %d",playButton.hidden);
}
}
add a custom cell and Handle button click event and hide/unhide functionality on cell level
I have this collapsable UITableView where there is a UITextField and a UIButton in the last cell in each table section. I would like to send the text in the UITextField to the function that is called by the UIButton that is next to it in the same cell, but I am baffled in how to achieve this. Thanks in advance for the help!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:nil];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if ([self tableView:_tableView canCollapseSection:indexPath.section])
{
int num = 1;
if (self.chat[indexPath.section - 1][#"num"] != nil)
num = [self.chat[indexPath.section - 1][#"num"] intValue] + 1;
if (!indexPath.row)
{
cell.textLabel.text = self.chat[indexPath.section - 1][#"msg"]; // only top row showing
if ([expandedSections containsIndex:indexPath.section])
{
cell.accessoryView = [DTCustomColoredAccessory accessoryWithColor:[UIColor grayColor] type:DTCustomColoredAccessoryTypeUp];
}
else
{
cell.accessoryView = [DTCustomColoredAccessory accessoryWithColor:[UIColor grayColor] type:DTCustomColoredAccessoryTypeDown];
}
}
else if (indexPath.row < num && indexPath.row >= 1)
{
cell.textLabel.text = self.chat[indexPath.section - 1][key];
cell.accessoryView = nil;
}
else
{
///////////////////////////////////////////
////////This is the important part/////////
///////////////////////////////////////////
UITextField *field = [[UITextField alloc] initWithFrame:CGRectMake(14, 6, 245, 31)];
self.sendButton = [[UIButton alloc] initWithFrame:CGRectMake(265, 1, 50, 40)];
[self.sendButton setTitle:#"Reply" forState:UIControlStateNormal];
[self.sendButton setTitleColor:UIColorFromRGB(0x960f00) forState:UIControlStateNormal];
[cell addSubview:self.sendButton];
[self.sendButton addTarget:self action:#selector(sendReply:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:field];
cell.accessoryView = nil;
}
}
else
{
cell.accessoryView = nil;
cell.textLabel.text = #"Normal Cell";
}
return cell;
}
Give some unique tag to textfield and button by below way:
///////////////////////////////////////////
////////This is the important part/////////
///////////////////////////////////////////
UITextField *field = [[UITextField alloc] initWithFrame:CGRectMake(14, 6, 245, 31)];
self.sendButton = [[UIButton alloc] initWithFrame:CGRectMake(265, 1, 50, 40)];
[self.sendButton setTitle:#"Reply" forState:UIControlStateNormal];
[self.sendButton setTitleColor:UIColorFromRGB(0x960f00) forState:UIControlStateNormal];
self.sendButton.tag = indexPath.section *1000 + indexPath.row;
[cell addSubview:self.sendButton];
[self.sendButton addTarget:self action:#selector(sendReply:) forControlEvents:UIControlEventTouchUpInside];
field.tag = self.sendButton.tag + 1;
[cell addSubview:field];
cell.accessoryView = nil;
Now on button event,
-(void) sendReply:(UIButton *)sender
{
UITextField *field = [YOOUR_TABLE_VIEW viewWithTag:sender.tag + 1];
//Do you coding here
}
Make a Custom UITableViewCell that has uitextfield and a button on it and make a protocol/delegate of that custom uitableviewcell you've created.. so you can have more control of your code and the event of your button in the future..
check this tutorial: http://www.codigator.com/tutorials/ios-uitableview-tutorial-custom-cell-and-delegates/
cheers
For this,
In cellForRowAtIndexPath: method where you are allocating the send button add one line just to give some identifier to send button as below,
[self.sendButton setAccessibilityIdentifier:[NSString stringWithFormat:#"%d#%d",indexPath.row,indexPath.section]];
Now, in sendReply: method,
//First get the row and section information
NSString *str=[sender accessibilityIdentifier];
NSArray *arr=[str componentsSeparatedByString:#"#"];
//Get the index path
NSIndexPath *iRowId =[NSIndexPath indexPathForRow:[[arr objectAtIndex:0] intValue] inSection:[arr objectAtIndex:1] intValue]];
//get the cell
UITableViewCell *objCell=(UITableViewCell*)[tblviwBasketCell cellForRowAtIndexPath:iRowId];
Now objCell will be the cell in which you have added the button and text view. so get the subviews of objCell and access the textfield to get the text.
As you say, there is a text field in each section. You should set the tag of your UIButton and UITextField same as indexPath.section.
Then, in the target method, use this tag value to get the relevant cell from the relevant section, and iterate over it's subviews to get your textField.
In the target method, you should do something like this:
- (void) sendReply:(id)sender {
int section = [(UIButton*)sender tag];
int row = [myTableView numberOfRowsInSection:section] - 1;//assuming it is the last cell in the section that contains your textField.
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:row inSection:section];
UITableViewCell* cell = [myTableView cellForRowAtIndexPath:indexPath];
for (UIView* vu in cell.subviews) {
if ([vu isKindOfClass:[UITextField class]]) {
NSString* textString = [(UITextField*)vu text];
//perform any tasks you want with the text now
}
}
}
You can simply use viewWithTag:, since it does an iterative search, but all the extra code is to avoid iterating over all the cells before reaching your relevant cell.
i am trying to use UIMenuController to perform a custom action on the table cell, from which the UIMenuController triggered by long time press.
I registered UILongPressGestureRecognizer in the viewDidLoad method in my subclass of UITableViewController and added custom item with #selector(handleMyAction).
- (void)viewDidLoad
{
[super viewDidLoad];
[self.refreshControl addTarget:self action:#selector(refreshView:) forControlEvents:UIControlEventValueChanged];
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPress:)];
longPressGesture.minimumPressDuration = .5;
longPressGesture.delegate = self;
[self.tableView addGestureRecognizer:longPressGesture];
}
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
if(gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
CGPoint point = [gestureRecognizer locationInView:self.tableView];
NSIndexPath * indexPath = [self.tableView indexPathForRowAtPoint:point];
if(indexPath == nil) return ;
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
UIMenuItem *it = [[UIMenuItem alloc] initWithTitle:#"My Action on this cell" action:#selector(handleMyAction:)];
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setMenuItems:[NSArray arrayWithObjects:it, nil]];
[menu setTargetRect:cell.frame inView:cell.superview];
[menu setMenuVisible:YES animated:YES];
[self becomeFirstResponder];
}
}
I also override the
- (BOOL)canBecomeFirstResponder{
return YES;
}
When I press on one cell the context menu with the custom entry displays properly. BUT, the problem is how can I implement the method to handle the custom action, which should be performed on the tapped cell.
- (void)handleMyAction:(id)sender
{
NSLog(#"Action triggered, however need some way to refer the tapped cell");
}
Because the only information i can get in this method is the sender, which is the UIMenuController self, but i have no idea how can get the cell, on which the Menu triggered, so i can do further action regarding the cell itself.
Could some one help me on that?
Thanks.
Hai
Well you're currently adding the UIGestureRecognizer to the tableview itself. Why not add it to each cell instead (in cellForRowAtIndexPath when they are setup) ?
Thanks valheru. I find a "nice" approach to achieve that:)
Step one: In MyTableViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPress:)];
longPressGesture.minimumPressDuration = .5;
longPressGesture.delegate = self;
[self.view addGestureRecognizer:longPressGesture];
}
which register the gesture recognizer of the long press on the table view controller.
- (BOOL)canBecomeFirstResponder
{
return YES;
}
which allows MyTableViewController response the long press and popup the context menu.
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
if(gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
CGPoint point = [gestureRecognizer locationInView:self.tableView];
NSIndexPath * indexPath = [self.tableView indexPathForRowAtPoint:point];
if(indexPath == nil) return ;
MyCell *cell = (MyCell *)[self.tableView cellForRowAtIndexPath:indexPath];
UIMenuItem *determine = [[UIMenuItem alloc] initWithTitle:#"My Action on this cell" action:#selector(handleMyAction:)];
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setMenuItems:[NSArray arrayWithObjects:determine, nil]];
[menu setTargetRect:cell.frame inView:cell.superview];
[menu setMenuVisible:YES animated:YES];
[cell becomeFirstResponder]; //here set the cell as the responder of the menu action
cell.delegate = self;// this is optional, if you don't want to implement logic in cell class
}
}
create the UIMenuController and popup when i long press the cell.
-(void)handleMyAction: (UITableViewCell *)cell
{
NSLog(#"%#", cell);
}
this function will be called later from the cell which is pressed.
Step two: Create a subclass of UITableViewCell named MyCell
In MyCell.h defines the table view controller the cell belongs as the delegate of the cell. And the callback function when the menu entry clicked
#property (nonatomic, strong) MyTableViewController *delegate;
-(void)handleMyAction:(id)sender;
in MyCell.m
- (BOOL)canBecomeFirstResponder
{
return YES;
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
if(action == #selector(handleMyAction:))
{
return YES;
}
return NO;
}
allows the MyCell to be the first responder and response the handleMyAction action by clicking on menu entry.
-(void)handleMyAction:(id)sender
{
[self.delegate handleMyAction:self]; //it's a coincidence both functions have the same name:)
}
this is the definition of the callback function, which will be called when click on the menu entry, and it in turn call the handMyAction function in the delegate of the cell (MyTableViewController, where the logic regarding the cell could be implemented.)
First declare a NSIndexPath type as a class variable.
#property (nonatomic, strong) NSIndexPath *savedIndexPathForThePressedCell;
Now in the Long press gesture recognizer function, get the TableViewCell using the recognizer view. Now save the IndexPath for the TableViewCell
- (void)longPressGestureFunction:(UILongPressGestureRecognizer *)recognizer
{
UITableViewCell *lTableViewCell = (UITableViewCell *)recognizer.view;
[lTableViewCell becomeFirstResponder];
/*Save the Indexpath of the cell pressed*/
self.savedIndexPathForThePressedCell = [mTableView indexPathForCell:lTableViewCell];
if (recognizer.state == UIGestureRecognizerStateBegan)
{
UIMenuItem *MenuDelete = [[UIMenuItem alloc] initWithTitle:#"Delete" action:#selector(Delete:)];
UIMenuItem *MenuForward = [[UIMenuItem alloc] initWithTitle:#"Forward" action:#selector(Forward:)];
UIMenuItem *MenuAddToContacts = [[UIMenuItem alloc] initWithTitle:#"Add To Contacts" action:#selector(addToContacts:)];
mSharedMenu = [UIMenuController sharedMenuController];
[mSharedMenu setMenuItems:[NSArray arrayWithObjects: MenuDelete, MenuForward, nil]];
[mSharedMenu setMenuVisible:YES animated:YES];
}
Now in the Menu selector method, select the row based on the saved indexPath.
- (void)Delete:(id)sender {
// NSLog(#"\n Delete Selected \n");
[mTableView setEditing:YES animated:YES];
[mTableView selectRowAtIndexPath:self.savedIndexPathForThePressedCell animated:YES scrollPosition:UITableViewScrollPositionNone];
}
I hope this helps!!!
I want to hide a label of a cell in a tableview.
(void)handleSwipeRight:(UISwipeGestureRecognizer *)gestureRecognizer
{
//Get location of the swipe
CGPoint location = [gestureRecognizer locationInView:self.tableView];
//Get the corresponding index path within the table view
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
//Check if index path is valid
if(indexPath)
{
//Get the cell out of the table view
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
//Update the cell or model
displayLabel.hidden = TRUE;
[cell setNeedsDisplay];
}
}
This code is hiding the label in the last cell as I failed to specify the code to hide the swiped cell's label.
Help to specify the swiped cell label to hide.
displayLabel.hidden = TRUE;
I need a replacement for this code.
You can try below code its working perfectly on my side:
- (void)viewDidLoad
{
UISwipeGestureRecognizer *recog = [[UISwipeGestureRecognizer alloc]initWithTarget:self
action:#selector(handleSwipeRight:)];
recog.delegate = self;
[recog setDirection:UISwipeGestureRecognizerDirectionRight];
[testTable addGestureRecognizer:recog];
// add the swipe gesture recognizer to tableview;
[super viewDidLoad];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 7;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
UILabel *aLabel = [[[UILabel alloc]init]autorelease];
aLabel.frame = CGRectMake(5, 0, 100, 40);
aLabel.text = [NSString stringWithFormat:#"aLabel %d",indexPath.row+1];
aLabel.tag = 1;//tag the labels
[cell.contentView addSubview:aLabel];
UILabel *bLabel = [[[UILabel alloc]init]autorelease];
bLabel.frame = CGRectMake(110, 0, 100, 40);
bLabel.text = [NSString stringWithFormat:#"bLabel %d",indexPath.row+1];
bLabel.tag = 2;//tag the label
[cell.contentView addSubview:bLabel];
UILabel *cLabel = [[[UILabel alloc]init]autorelease];
cLabel.frame = CGRectMake(215, 0, 100, 40);
cLabel.text = [NSString stringWithFormat:#"cLabel %d",indexPath.row+1];
cLabel.tag = 3;//tag the label
[cell.contentView addSubview:cLabel];
}
return cell;
}
-(void)handleSwipeRight:(UISwipeGestureRecognizer *)gestureRecognizer
{
//Get location of the swipe
CGPoint location = [gestureRecognizer locationInView:testTable];
//Get the corresponding index path within the table view
NSIndexPath *indexPath = [testTable indexPathForRowAtPoint:location];
//Check if index path is valid
if(indexPath)
{
//Get the cell out of the table view
UITableViewCell *cell = [testTable cellForRowAtIndexPath:indexPath];
for (id label in cell.contentView.subviews)
{
if ([label isMemberOfClass:[UILabel class]])
{
UILabel *referedLabel = (UILabel*)label;
if (referedLabel.tag == 2) //tag of bLabel;
{
referedLabel.hidden = YES;
}
}
}
}
}
I think displayLabel is pointing to label in last cell of your table. Where you are setting value to displayLabel.
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
//Update the cell or model
//You should get label from cell here. Currently displayLabel may be pointing to label in last cell, if I am correct you are assigning value to displaylabel in cellForRowAtIndexPath or in any other method.
displayLabel.hidden = TRUE;
[cell setNeedsDisplay];
Change your method to this:
-(void)handleSwipeRight:(UISwipeGestureRecognizer *)gestureRecognizer
{
//Get location of the swipe
CGPoint location = [gestureRecognizer locationInView:self.tableView];
//Get the corresponding index path within the table view
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
//Check if index path is valid
if(indexPath)
{
// If you created a custom cell with a
// displayLabel property, change the pointer
// type from UITableViewCell to that type
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
cell.displayLabel.hidden = YES;
// Use the following three lines instead, if your cell style is "Subtitle"
// cell.textLabel.hidden = YES;
// cell.imageView.hidden = YES;
// cell.detailTextLabel.hidden = YES;
[cell setNeedsDisplay];
}
}