2009-05-15 6 views
136

Utilizzo un UITableViewCell personalizzato, incluso lo stesso per accessoryView della cella. La mia configurazione per l'accessoryView avviene per la via di qualcosa di simile:Utilizzo di un'immagine personalizzata per l'accessorio di UITableViewCellVisualizzazione e risposta a UITableViewDelegate

UIImage *accessoryImage = [UIImage imageNamed:@"accessoryDisclosure.png"]; 
UIImageView *accImageView = [[UIImageView alloc] initWithImage:accessoryImage]; 
accImageView.userInteractionEnabled = YES; 
[accImageView setFrame:CGRectMake(0, 0, 28.0, 28.0)]; 
self.accessoryView = accImageView; 
[accImageView release]; 

Anche quando viene inizializzato il cellulare, utilizzando initWithFrame:reuseIdentifier: ho assicurato per impostare la seguente proprietà:

self.userInteractionEnabled = YES; 

Purtroppo nel mio UITableViewDelegate, il mio metodo tableView:accessoryButtonTappedForRowWithIndexPath: (prova a ripetere che 10 volte) non viene attivato. Il delegato è sicuramente cablato correttamente.

Cosa può essere che manchi?

Grazie a tutti.

risposta

226

Purtroppo questo metodo non viene chiamato a meno che il tipo di pulsante interno fornito quando si utilizza uno dei tipi predefiniti sia TAPpato. Per utilizzare il proprio, dovrai creare il tuo accessorio come un pulsante o un'altra sottoclasse di UIControl (ti consigliamo un pulsante utilizzando -buttonWithType:UIButtonTypeCustom e l'impostazione dell'immagine del pulsante, anziché utilizzare UIImageView).

Ecco alcune cose che uso in Outpost, che personalizza abbastanza dei widget standard (solo leggermente, per abbinarci alla colorazione verde acqua) che ho terminato facendo la mia sottoclasse intermediaria UITableViewController per contenere il codice utilità per tutte le altre visualizzazioni tabella da usare (ora sottoclasse OPTableViewController).

In primo luogo, questa funzione restituisce un nuovo pulsante dettaglio divulgazione utilizzando il nostro grafico personalizzato:

- (UIButton *) makeDetailDisclosureButton 
{ 
    UIButton * button = [UIButton outpostDetailDisclosureButton]; 

[button addTarget: self 
       action: @selector(accessoryButtonTapped:withEvent:) 
    forControlEvents: UIControlEventTouchUpInside]; 

    return (button); 
} 

Il pulsante chiamerà questa routine quando è fatto, che poi alimenta la routine UITableViewDelegate standard per i pulsanti accessori:

- (void) accessoryButtonTapped: (UIControl *) button withEvent: (UIEvent *) event 
{ 
    NSIndexPath * indexPath = [self.tableView indexPathForRowAtPoint: [[[event touchesForView: button] anyObject] locationInView: self.tableView]]; 
    if (indexPath == nil) 
     return; 

    [self.tableView.delegate tableView: self.tableView accessoryButtonTappedForRowWithIndexPath: indexPath]; 
} 

Questa funzione individua la riga ottenendo la posizione nella vista tabella di un tocco dall'evento fornito dal pulsante e chiedendo la vista tabella per il percorso dell'indice della riga in quel punto.

+0

Grazie Jim. È un peccato che ho passato più di 20 minuti a chiedermi perché non posso farlo con un imageView personalizzato. Ho appena visto come farlo sull'app Accessory di Apple. La tua risposta è ben spiegata e documentata, quindi la sto prendendo in considerazione e la tengo in giro. Grazie ancora. :-) –

+0

Questa soluzione è geniale! +1 –

+11

Solo per gli altri che guardano questa risposta, puoi anche semplicemente mettere un tag sul pulsante che corrisponde alla riga (se hai più sezioni, dovrai fare un po 'di matematica) e poi tirare fuori il tag da il pulsante nella funzione. Penso che potrebbe essere un po 'più veloce del calcolo del tocco. – RyanJM

1

È necessario utilizzare un UIControl per ottenere correttamente la distribuzione di eventi (ad esempio un UIButton) anziché il semplice UIView/UIImageView.

75

ho trovato questo sito per essere molto utile: custom accessory view for your uitableview in iphone

In breve, utilizzare questo in cellForRowAtIndexPath::

UIImage *image = (checked) ? [UIImage imageNamed:@"checked.png"] : [UIImage imageNamed:@"unchecked.png"]; 

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 
CGRect frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height); 
button.frame = frame; 
[button setBackgroundImage:image forState:UIControlStateNormal]; 

[button addTarget:self action:@selector(checkButtonTapped:event:) forControlEvents:UIControlEventTouchUpInside]; 
button.backgroundColor = [UIColor clearColor]; 
cell.accessoryView = button; 

quindi, implementare questo metodo:

- (void)checkButtonTapped:(id)sender event:(id)event 
{ 
    NSSet *touches = [event allTouches]; 
    UITouch *touch = [touches anyObject]; 
    CGPoint currentTouchPosition = [touch locationInView:self.tableView]; 
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint: currentTouchPosition]; 

    if (indexPath != nil) 
    { 
     [self tableView: self.tableView accessoryButtonTappedForRowWithIndexPath: indexPath]; 
    } 
} 
+3

Grazie! Questo ha fatto per me! – Marius

+4

Direi +1 per questo perché è ciò che Apple consiglia di fare nel loro codice di esempio nei loro documenti: http://developer.apple.com/library/ios/#samplecode/Accessory/Listings/MyTableViewController_m.html#// apple_ref/doc/uid/DTS40008066-MyTableViewController_m-DontLinkElementID_6 – cleverbit

+0

L'impostazione del telaio era il pezzo mancante per me. Puoi anche solo impostare Image (anziché lo sfondo) finché non vuoi anche alcun testo. –

7

Il mio approccio è creare una sottoclasse UITableViewCell e incapsulare la logica che chiamerà il solito metodo UITableViewDelegate al suo interno.

// CustomTableViewCell.h 
@interface CustomTableViewCell : UITableViewCell 

- (id)initForIdentifier:(NSString *)reuseIdentifier; 

@end 

// CustomTableViewCell.m 
@implementation CustomTableViewCell 

- (id)initForIdentifier:(NSString *)reuseIdentifier; 
{ 
    // the subclass specifies style itself 
    self = [super initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuseIdentifier]; 
    if (self) { 
     // get the button elsewhere 
     UIButton *accBtn = [ViewFactory createTableViewCellDisclosureButton]; 
     [accBtn addTarget: self 
        action: @selector(accessoryButtonTapped:withEvent:) 
     forControlEvents: UIControlEventTouchUpInside]; 
     self.accessoryView = accBtn; 
    } 
    return self; 
} 

#pragma mark - private 

- (void)accessoryButtonTapped:(UIControl *)button withEvent:(UIEvent *)event 
{ 
    UITableViewCell *cell = (UITableViewCell*)button.superview; 
    UITableView *tableView = (UITableView*)cell.superview; 
    NSIndexPath *indexPath = [tableView indexPathForCell:cell]; 
    [tableView.delegate tableView:tableView accessoryButtonTappedForRowWithIndexPath:indexPath]; 
} 

@end 
+0

Questa è la migliore risposta. Ma 'button.superview',' cell.superview' e '[tableView.delegate tableView: ...]' non sono abbastanza sicuri. – iwill

1

Con Yanchenko approccio che ho dovuto aggiungere: [accBtn setFrame:CGRectMake(0, 0, 20, 20)];

Se si sta utilizzando il file XI ter personalizzare il TableCell poi initWithStyle: reuseIdentifier: non otterrete chiamato.

Invece ignorare:

-(void)awakeFromNib 
{ 
//Put your code here 

[super awakeFromNib]; 

} 
2
  1. definire una macro per i tag di pulsanti:

    #define AccessoryViewTagSinceValue 100000 // (AccessoryViewTagSinceValue * sections + rows) must be LE NSIntegerMax 
    
  2. pulsante Crea e impostare il cell.accessoryView durante la creazione di una cellula

    UIButton *accessoryButton = [UIButton buttonWithType:UIButtonTypeContactAdd]; 
    accessoryButton.frame = CGRectMake(0, 0, 30, 30); 
    [accessoryButton addTarget:self action:@selector(accessoryButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; 
    cell.accessoryView = accessoryButton; 
    
  3. Set cell.accessoryView.tag da indexPath nel metodo UITableViewDataSource -tableView: cellForRowAtIndexPath:

    cell.accessoryView.tag = indexPath.section * AccessoryViewTagSinceValue + indexPath.row; 
    
  4. gestore di eventi per i pulsanti

    - (void) accessoryButtonTapped:(UIButton *)button { 
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:button.tag % AccessoryViewTagSinceValue 
                   inSection:button.tag/AccessoryViewTagSinceValue]; 
    
        [self.tableView.delegate tableView:self.tableView accessoryButtonTappedForRowWithIndexPath:indexPath]; 
    } 
    
  5. Implementare il metodo UITableViewDelegate

    - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath { 
        // do sth. 
    } 
    
+0

Nessuno dovrebbe usare 'tag' a meno che, quando è assolutamente necessario, cerchi un'altra soluzione. – Lifely

2

Quando si tocca il pulsante, si esegue il coul d averlo chiamare il seguente metodo all'interno di una sottoclasse UITableViewCell

-(void)buttonTapped{ 
    // perform an UI updates for cell 

    // grab the table view and notify it using the delegate 
    UITableView *tableView = (UITableView *)self.superview; 
    [tableView.delegate tableView:tableView accessoryButtonTappedForRowWithIndexPath:[tableView indexPathForCell:self]]; 

} 
3

Un'estensione alla risposta di Jim Dovey sopra:

Fare attenzione quando si utilizza un UISearchBarController con l'UITableView. In tal caso, verificare lo self.searchDisplayController.active e utilizzare self.searchDisplayController.searchResultsTableView anziché self.tableView. Altrimenti si otterranno risultati imprevisti quando searchDisplayController è attivo, soprattutto quando si scorre i risultati della ricerca.

Ad esempio:

- (void) accessoryButtonTapped:(UIControl *)button withEvent:(UIEvent *)event 
{ 
    UITableView* tableView = self.tableView; 
    if(self.searchDisplayController.active) 
     tableView = self.searchDisplayController.searchResultsTableView; 

    NSIndexPath * indexPath = [tableView indexPathForRowAtPoint:[[[event touchesForView:button] anyObject] locationInView:tableView]]; 
    if(indexPath) 
     [tableView.delegate tableView:tableView accessoryButtonTappedForRowWithIndexPath:indexPath]; 
} 
0

Come di iOS 3.2 è possibile evitare i pulsanti che altri qui sono raccomandare e di utilizzare invece il vostro UIImageView con un riconoscitore rubinetto gesto. Assicurati di abilitare l'interazione dell'utente, che è disattivata per impostazione predefinita in UIImageViews.

Problemi correlati