2010-03-21 10 views

risposta

28

Il metodo prima di iOS 5 è quello di ottenere un'istanza condivisa del UIMenuController, impostare il rettangolo di destinazione e di visualizzare e chiamare -setMenuVisible:animated:. Ricordare di implementare -canPerformAction:withSender: nel proprio risponditore.


Il metodo dopo iOS 5 (precedentemente disponibile come funzionalità non documentata) è quello di implementare questi 3 metodi nell'origine dati (vedere https://developer.apple.com/reference/uikit/uitableviewdelegate#1653389).

-(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; 
+0

Grazie! Il metodo non documentato è esattamente quello che stavo cercando. Il metodo "ufficiale" è piuttosto goffo. Si spera che venga presto documentato. Non è ideale che non sia documentato, ma in questo caso è solo implementando il protocollo, non chiamando un metodo, quindi si spera che sia sicuro (er). –

+0

Perché questi metodi non sono ancora documentati? Sono una specie di metodi privati? Se lo sono, la tua app potrebbe non essere accettata dall'app store. – dombesz

+0

Questi sono documentati come iOS 5.0 come parte del protocollo UITableViewDelegate: http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UITableViewDelegate_Protocol/Reference/Reference.html. –

14

La sottoclasse UITableViewCell potrebbe assomigliare a questo

@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 

E i metodi UITableView delegato sono come

- (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]; 
} 
+0

Grazie per la risposta. Questo è un buon modo per farlo "ufficialmente", immagino, ma ciò che non mi piace è che mostra la vista Copia quando selezionata, dove l'app Rubrica mostra la vista di copia quando è trattenuta per X secondi. Questo non è un problema con la tua soluzione, ma piuttosto con l'API. Grazie mille per il tuo aiuto. –

+0

Quando provo questa soluzione sembra funzionare, ma dopo che il menu è mostrato, ulteriori chiamate a [self.tableView reloadData] non chiamano i callback UITableViewDataSource: numberOfSections, ecc.Sembra che la chiamata a diventare FirstResponder sia il metodo che whacks il TableView dal ricaricare, ma la chiamata a diventareFirstResponder è necessaria per mostrare il menu. È difficile credere che qualcos'altro non stia succedendo. Molto confuso. Forse inizierò un nuovo progetto per vedere se riesco a riprodurlo da solo. – Daniel

+0

Ho riprodotto il problema in un progetto nuovo e pulito. Nella mia UITableViewCell personalizzata avevo implementato: - (BOOL) resignFirstResponder perché pensavo che sarebbe stato un buon posto per cancellare le voci del menu personalizzato da sharedMenuController. Se non si eliminano le voci di menu personalizzate, vengono associate ad altri campi UIText nella stessa vista, dove non hanno senso. In ogni caso, anche se il mio resignFirstResponder non fa altro che restituire YES, causa comunque il fallimento delle chiamate [tableView reloadData] successive. Questo è molto strano per me. Immagino che cercherò un altro posto per cancellare il menu. – Daniel

34

V'è ora l'interfaccia ufficiale per la visualizzazione dei menu cellulari UITableView in iOS 5. Esempio (dal delegato del tavolo):

- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    return YES; 
} 

- (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender 
{ 
    return (action == @selector(copy:)); 
} 

- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender 
{ 
    if (action == @selector(copy:)){ 
     UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; 
     [[UIPasteboard generalPasteboard] setString:cell.textLabel.text]; 
    } 
} 

Ho provato a modificare il controller condiviso di UIMenuController per aggiungere la mia voce di menu, e sono stato in grado di aggiungerlo e ottenere il messaggio canPerformAction, ma restituire SÌ non ha aiutato; Non ero in grado di far apparire la mia voce di menu personalizzata. Dai miei esperimenti, sembra che solo Copia, Taglia e Incolla siano supportati. [EDIT Poiché è stato pubblicato, ho imparato come aggiungere voci di menu personalizzate.]

Si noti che questo funziona solo se tutti e tre i metodi delegati sono implementati.

+0

Disponibile da iOS 5.0. –

+4

Aggiungilo sotto NSLog per copiare su pasteboard UITableViewCell * cell = [self tableView: tableView cellForRowAtIndexPath: indexPath]; [[UIPasteboard generalPasteboard] setString: cell.detailTextLabel.text]; – malaki1974

+0

Sì, era essenziale quindi ho modificato la sua risposta con :-) – malhal

9
#pragma mark - COPY/PASTE Cell Text via Menu 

- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    return YES; 
} 

- (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender 
{ 
    return (action == @selector(copy:)); 
} 

- (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]; 
    } 
} 
13

Ecco la sintassi Swift per la copia detailTextLabel.

override func tableView(_ tableView: UITableView, shouldShowMenuForRowAt indexPath: IndexPath) -> Bool { 
    return (tableView.cellForRow(at: indexPath)?.detailTextLabel?.text) != nil 
} 

override func tableView(_ tableView: UITableView, canPerformAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) -> Bool { 
    return action == #selector(copy(_:)) 
} 

override func tableView(_ tableView: UITableView, performAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) { 
    if action == #selector(copy(_:)) { 
     let cell = tableView.cellForRow(at: indexPath) 
     let pasteboard = UIPasteboard.general 
     pasteboard.string = cell?.detailTextLabel?.text 
    } 
} 
Problemi correlati