-
Notifications
You must be signed in to change notification settings - Fork 1
DD 4.6. Displaying Context Menus on Table View Cells
You want to give your users the ability to use copy/paste options among other operations that they can choose, by holding down one of their fingers on a table view cell in your app.
Implement the following three methods of the UITableViewDelegate protocol in the delegate object of your table view:
tableView:shouldShowMenuForRowAtIndexPath: The return value of this method is of type BOOL. If you return YES from this method, iOS will display the context menu for the table view cell whose index gets passed to you through the shouldShowMenuForRowAtIndexPath parameter.
tableView:canPerformAction:forRowAtIndexPath:withSender: The return value of this method is also of type BOOL. Once you allow iOS to display a context menu for a table view cell, iOS will call this method multiple times and pass you the selector of the action that you can choose to display in the context menu or not. So, if iOS wants to ask you whether you would like to show the Copy menu to be displayed to the user, this method will get called in your table view’s delegate object and the canPerformAction parameter of this method will be equal to @selector(copy:).
tableView:performAction:forRowAtIndexPath:withSender: Once you allow a certain action to be displayed in the context menu of a table view cell, when the user picks that action from the menu, this method will get called in your table view’s delegate object. In here, you must do whatever needs to be done to satisfy the user’s request. For instance, if it is the Copy menu that the user has selected, you will need to use a pasteboard to place the chosen table view cell’s content into the pasteboard.
I suggest that we first see what actions are actually available for a context menu on a table view cell, so let’s create our table view and then display a few cells inside it:
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return 3; } - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ UITableViewCell *cell = nil; cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; cell.textLabel.text = [[NSString alloc] initWithFormat:@"Section %ld Cell %ld", (long)indexPath.section, (long)indexPath.row]; return cell; } - (void)viewDidLoad{ [super viewDidLoad]; self.myTableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; [self.myTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:CellIdentifier]; self.myTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.myTableView.dataSource = self; self.myTableView.delegate = self; [self.view addSubview:self.myTableView]; }
Now we will implement the three aforementioned methods defined in the UITable ViewDelegate protocol and simply convert the available actions (of type SEL) to strings and print them out to the console:
- (BOOL) tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath{ /* Allow the context menu to be displayed on every cell */ return YES; } - (BOOL) tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender{ NSLog(@"%@", NSStringFromSelector(action)); /* Allow every action for now */ return YES; } - (void) tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender{ /* Empty for now */ }
Now run your app in the simulator or on the device. You will see three cells loaded into the table view. Hold down your finger (if on a device) or your pointer (if using iOS Simulator) on one of the cells and observe what gets printed out to the console window: cut: copy: select: selectAll: paste: delete: _promptForReplace: _showTextStyleOptions: _define: _addShortcut: _accessibilitySpeak: _accessibilitySpeakLanguageSelection: _accessibilityPauseSpeaking: makeTextWritingDirectionRightToLeft: makeTextWritingDirectionLeftToRight:
These are all the actions that iOS will allow you to show your users, should you need them. So for instance, if you would like to allow your users to have the Copy option, in the tableView:canPerformAction:forRowAtIndexPath:withSender: method, sim‐ ply find out which action iOS is asking your permission for before displaying it, and either return YES or NO:
- (BOOL) tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender{ if (action == @selector(copy:)){ return YES; } return NO; }
The next step is to intercept what menu item the user actually selected from the context menu. Based on this information, we can then take appropriate action. For instance, if the user selected the Copy item in the context menu, then we can use UIPasteBoard to copy that cell into the pasteboard for later use:
- (void) tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender{ if (action == @selector(copy:)){ UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; UIPasteboard *pasteBoard = [UIPasteboard generalPasteboard]; [pasteBoard setString:cell.textLabel.text]; } }