J'utilise un UITableViewCell dessiné personnalisé, y compris le même pour le accessoryView
de la cellule. Ma configuration pour l’accessoire 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];
Également lorsque la cellule est initialisée, en utilisant initWithFrame:reuseIdentifier:
Je me suis assuré de définir la propriété suivante:
self.userInteractionEnabled = YES;
Malheureusement, dans mon UITableViewDelegate, mon tableView:accessoryButtonTappedForRowWithIndexPath:
méthode (essayez de répéter cela 10 fois) ne se déclenche pas. Le délégué est définitivement câblé correctement.
Que peut-il éventuellement manquer?
Merci a tous.
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 sélectionné. Pour utiliser les vôtres, vous devez créer votre accessoire sous forme de bouton ou de sous-classe UIControl (je recommanderais un bouton utilisant -buttonWithType:UIButtonTypeCustom
et en définissant l'image du bouton, plutôt que d'utiliser un UIImageView).
Voici quelques éléments que j'utilise dans Outpost, qui personnalise assez de widgets standard (juste un peu, pour correspondre à notre couleur turquoise) que j'ai finalement créés dans ma propre sous-classe intermédiaire UITableViewController OPTableViewController).
Tout d'abord, cette fonction renvoie un nouveau bouton de divulgation des détails à l'aide de notre graphique personnalisé:
- (UIButton *) makeDetailDisclosureButton
{
UIButton * button = [UIButton outpostDetailDisclosureButton];
[button addTarget: self
action: @selector(accessoryButtonTapped:withEvent:)
forControlEvents: UIControlEventTouchUpInside];
return ( button );
}
Le bouton appellera cette routine à la fin, qui alimentera 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 dans la vue table d'une touche à partir de l'événement fourni par le bouton et en demandant à la vue table le chemin d'index de la ligne à ce point.
J'ai trouvé ce site très utile: vue accessoire personnalisée pour votre uitableview dans iphone
En bref, utilisez ceci 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, implémentez 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];
}
}
Mon approche consiste à créer une sous-classe UITableViewCell
et à encapsuler la logique qui appellera la méthode habituelle de UITableViewDelegate
.
// 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
Une extension de la réponse de Jim Dovey ci-dessus:
Soyez prudent lorsque vous utilisez un UISearchBarController avec votre UITableView. Dans ce cas, vous voulez vérifier self.searchDisplayController.active
et utilise self.searchDisplayController.searchResultsTableView
au lieu de self.tableView
. Sinon, vous obtiendrez des résultats inattendus lorsque 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];
}
Définissez une macro pour les balises de boutons:
#define AccessoryViewTagSinceValue 100000 // (AccessoryViewTagSinceValue * sections + rows) must be LE NSIntegerMax
Créer un bouton et définir 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;
Définissez cell.accessoryView.tag avec indexPath dans la méthode UITableViewDataSource -tableView: cellForRowAtIndexPath:
cell.accessoryView.tag = indexPath.section * AccessoryViewTagSinceValue + indexPath.row;
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];
}
Implémenter la méthode UITableViewDelegate
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
// do sth.
}
Lorsque le bouton est exploité, vous pouvez le faire appeler la méthode suivante dans une sous-classe 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]];
}
Vous devez utiliser un UIControl
pour obtenir correctement la répartition d’événement (par exemple un UIButton
) au lieu de simple UIView/UIImageView
.
Avec l'approche Yanchenko, j'ai dû ajouter: [accBtn setFrame:CGRectMake(0, 0, 20, 20)];
Si vous utilisez un fichier xib pour personnaliser votre tableCell, initWithStyle: reuseIdentifier: ne sera pas appelé.
Au lieu de remplacer:
-(void)awakeFromNib
{
//Put your code here
[super awakeFromNib];
}
Depuis iOS 3.2, vous pouvez éviter les boutons recommandés par d’autres utilisateurs et utiliser votre UIImageView avec un outil de reconnaissance des gestes tactiles. Veillez à activer l'interaction utilisateur, désactivée par défaut dans UIImageViews.
Swift 5
Cette approche utilise le UIButton.tag
pour stocker le chemin indexPath en utilisant le transfert de bits de base. L'approche fonctionnera sur les systèmes 32 et 64 bits tant que vous n'avez pas plus de 65 535 sections ou lignes.
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellId")
let accessoryButton = UIButton(type: .custom)
accessoryButton.setImage(UIImage(named: "imageName"), for: .normal)
accessoryButton.sizeToFit()
accessoryButton.addTarget(self, action: #selector(handleAccessoryButton(sender:)), for: .touchUpInside)
let tag = (indexPath.section << 16) | indexPath.row
accessoryButton.tag = tag
cell?.accessoryView = accessoryButton
}
@objc func handleAccessoryButton(sender: UIButton) {
let section = sender.tag >> 16
let row = sender.tag & 0xFFFF
// Do Stuff
}