views:

458

answers:

2

Is there a simple way for subclasses of UITableViewCell to show the 'Copy' UIMenuController popup like in the Address book app (see screenshot), after the selection is held for a while?

address book

+3  A: 

The normal method is to get the UIMenuController's shared instance, set the target rect and view and call -setMenuVisible:animated:. Remeber to implement -canPerformAction:withSender: in your responder.


The undocumented method is to implement these 3 methods in your data source (see http://iphonedevwiki.net/index.php/UITableViewDataSource).

-(void)tableView:(UITableView*)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath*)indexPath withSender:(id)sender;
-(BOOL)tableView:(UITableView*)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath*)indexPath withSender:(id)sender;
-(BOOL)tableView:(UITableView*)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath*)indexPath; 
KennyTM
Thanks! The undocumented method is exactly what I was looking for. The "official" method is rather clunky. Hopefully it becomes documented soon.It isn't ideal that it is undocumented, but in this case it's just implementing the protocol, not calling a method, so hopefully it's safe(er).
William Denniss
+2  A: 

Your UITableViewCell subclass may look like this

@interface MenuTableViewCell : UITableViewCell {
}
- (IBAction)copy:(id)sender;
- (void)showMenu;

@end


@implementation MenuTableViewCell

- (BOOL)canBecomeFirstResponder {
    return YES;
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
    if (action == @selector(copy:)) {
        return YES;
    }
    return NO;
}
- (IBAction)copy:(id)sender {
}
- (void)showMenu {
    [[UIMenuController sharedMenuController] setMenuVisible:NO animated:YES];
    [self becomeFirstResponder];
    [[UIMenuController sharedMenuController] update];
    [[UIMenuController sharedMenuController] setTargetRect:CGRectZero inView:self];
    [[UIMenuController sharedMenuController] setMenuVisible:YES animated:YES];

}

@end

And the UITableView delegate methods are like

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    MenuTableViewCell *cell = (MenuTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[MenuTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }

    // Configure the cell.
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    MenuTableViewCell *cell = (MenuTableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
    [cell showMenu];
}
zonble
Thanks for the answer. This is a good way to do it "officially" I guess, but what I don't like is that it shows the Copy view when selected, where as the Address Book app shows the copy view when held for X seconds. This isn't an issue with your solution, but rather with the API. Thanks very much for your help.
William Denniss