143 votes

Utilisation d'une image personnalisée pour l'accessoryView d'un UITableViewCell et réponse à UITableViewDelegate

J'utilise un UITableViewCell dessiné de manière personnalisée, y compris la même chose pour les éléments de la cellule. accessoryView . Ma configuration pour le accessoryView se fait de la manière suivante :

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];

De même, lorsque la cellule est initialisée, en utilisant initWithFrame:reuseIdentifier: J'ai veillé à définir la propriété suivante :

self.userInteractionEnabled = YES;

Malheureusement, dans mon UITableViewDelegate, mon tableView:accessoryButtonTappedForRowWithIndexPath: (essayez de répéter cela 10 fois) n'est pas déclenchée. Le délégué est certainement câblé correctement.

Que peut-il bien manquer ?

Merci à tous.

229voto

Jim Dovey Points 8384

Malheureusement, cette méthode n'est appelée que si le type de bouton interne fourni lorsque vous utilisez l'un des types prédéfinis est touché. Pour utiliser le vôtre, vous devrez créer votre accessoire sous forme de bouton ou d'une autre sous-classe de UIControl (je recommanderais un bouton utilisant -buttonWithType:UIButtonTypeCustom et de définir l'image du bouton, plutôt que d'utiliser un UIImageView).

Voici quelques éléments que j'utilise dans Outpost, qui personnalise suffisamment les widgets standard (juste un peu, pour correspondre à notre couleur sarcelle) pour que je finisse par créer ma propre sous-classe intermédiaire UITableViewController pour contenir le code utilitaire que toutes les autres vues de table doivent utiliser (elles sous-classent maintenant OPTableViewController).

Tout d'abord, cette fonction renvoie un nouveau bouton de divulgation des détails utilisant notre graphique personnalisé :

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

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

    return ( button );
}

Le bouton appelle cette routine lorsqu'il a terminé, ce qui alimente ensuite la routine standard UITableViewDelegate pour les boutons accessoires :

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

Cette fonction localise la ligne en obtenant l'emplacement d'une touche dans la vue tableau à partir de l'événement fourni par le bouton et en demandant à la vue tableau le chemin d'index de la ligne à ce point.

77voto

Jon Points 2102

J'ai trouvé ce site web très utile : vue accessoire personnalisée pour votre uitableview dans iphone

En bref, utilisez-le dans 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;

alors, mettez en œuvre cette méthode :

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

7voto

yanchenko Points 24142

Mon approche consiste à créer un UITableViewCell et encapsuler la logique qui appellera les fonctions habituelles de l'interface utilisateur. UITableViewDelegate en son sein.

// 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

3voto

Zaggo Points 56

Une extension de la réponse de Jim Dovey ci-dessus :

Faites attention lorsque vous utilisez un UISearchBarController avec votre UITableView. Dans ce cas, vous devez vérifier si self.searchDisplayController.active et utiliser self.searchDisplayController.searchResultsTableView au lieu de self.tableView . Sinon, vous obtiendrez des résultats inattendus lorsque le searchDisplayController est actif, notamment lorsque les résultats de la recherche défilent.

Par exemple :

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

2voto

iwill Points 845
  1. Définir une macro pour les étiquettes des boutons :

    #define AccessoryViewTagSinceValue 100000 // (AccessoryViewTagSinceValue * sections + rows) must be LE NSIntegerMax
  2. Créer un bouton et définir le cell.accessoryView lors de la création d'une cellule

    UIButton *accessoryButton = [UIButton buttonWithType:UIButtonTypeContactAdd];
    accessoryButton.frame = CGRectMake(0, 0, 30, 30);
    [accessoryButton addTarget:self action:@selector(accessoryButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
    cell.accessoryView = accessoryButton;
  3. Définir cell.accessoryView.tag par indexPath dans la méthode UITableViewDataSource -tableView:cellForRowAtIndexPath :

    cell.accessoryView.tag = indexPath.section * AccessoryViewTagSinceValue + indexPath.row;
  4. Gestionnaire d'événements pour les boutons

    - (void) accessoryButtonTapped:(UIButton *)button {
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:button.tag % AccessoryViewTagSinceValue
                                                    inSection:button.tag / AccessoryViewTagSinceValue];
    
        [self.tableView.delegate tableView:self.tableView accessoryButtonTappedForRowWithIndexPath:indexPath];
    }
  5. Implémenter la méthode UITableViewDelegate

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X