J'ai une vue personnalisée à l'intérieur d'une UIBarButtonItem
, définie en appelant -initWithCustomView
. Mon élément de bouton de barre rend bien, mais lorsque je la touche, il n'appelle pas l'action sur l'objet cible.
Voici mon code:
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"someImage.png"]];
UIBarButtonItem *bbItem = [[UIBarButtonItem alloc] initWithCustomView:imageView];
self.navigationItem.leftBarButtonItem = bbItem;
[imageView release];
[bbItem setTarget:self];
[bbItem setAction:@selector(deselectAll)];
Je ne pense pas que la cible et l'action de UIBarButtonItem s'appliquent aux vues personnalisées. Essayez d’utiliser un UIButton au lieu de UIImageView et d’appliquer la cible et l’action au bouton.
Exemple de code dans Swift:
let button = UIButton(type: .Custom)
if let image = UIImage(named:"icon-menu.png") {
button.setImage(image, forState: .Normal)
}
button.frame = CGRectMake(0.0, 0.0, 30.0, 30.0)
button.addTarget(self, action: #selector(MyClass.myMethod), forControlEvents: .TouchUpInside)
let barButton = UIBarButtonItem(customView: button)
navigationItem.leftBarButtonItem = barButton
J'avais le même problème, mais j'étais opposé à l'utilisation d'une UIButton
au lieu d'une vue personnalisée pour ma UIBarButtonItem
(réponse de drawonward).
Vous pouvez également ajouter une UIGestureRecognizer
à la vue personnalisée avant de l'utiliser pour initialiser UIBarButtonItem
; cela semble fonctionner dans mon projet.
Voici comment je modifierais votre code d'origine:
UIImageView *SOCImageView = [[UIImageView alloc] initWithImage:
[UIImage imageNamed:@"cancel_wide.png"]];
UITapGestureRecognizer *tapGesture =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(deselectAll:)];
[SOCImageView addGestureRecognizer:tapGesture];
SOItem.leftBarButtonItem =
[[[UIBarButtonItem alloc] initWithCustomView:SOCImageView] autorelease];
[tapGesture release];
[SOCImageView release];
Voici comment je le fais fonctionner:
UIButton* infoButton = [UIButton buttonWithType: UIButtonTypeInfoLight];
[infoButton addTarget:self action:@selector(displayAboutUs) forControlEvents:UIControlEventTouchDown];
UIBarButtonItem* itemAboutUs =[[UIBarButtonItem alloc]initWithCustomView:infoButton];
…
Voici comment j'ai implémenté UIButton dans UIBarButtonItem:
UIButton *logoButton = [UIButton buttonWithType:UIButtonTypeCustom];
[logoButton setImage: [UIImage imageNamed:@"icon.png"] forState:UIControlStateNormal];
logoButton.frame = CGRectMake(0, 0, 30, 30);
[logoButton addTarget:self action:@selector(showAbout:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *barItem = [[UIBarButtonItem alloc] initWithCustomView:logoButton];
self.navigationItem.rightBarButtonItem = barItem;
[barItem release];
J'avais un problème similaire. Et j’ai suivi initialement le chemin suggéré par @drawnonward, mais j’ai eu des problèmes lorsque j’ai tenté de présenter un contrôleur popover sur un iPad: Utiliser un UIButton intégré comme vue personnalisée signifie que ce dernier est l’émetteur de La méthode presentPopoverFromBarButtonItem: du contrôleur popover se bloque lorsqu’il essaie de lui envoyer des messages qui ne s’appliquent qu’à UIBarButtonItems.
La solution que j'ai finalement trouvée était de voler l'image que je voulais utiliser (l'icône «info») d'un UIButton jetable et de construire mon UIBarButtonItem comme suit:
// Make the info button use the standard icon and hook it up to work
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeInfoLight];
UIBarButtonItem *barButton = [[[UIBarButtonItem alloc]
initWithImage:infoButton.currentImage
style:UIBarButtonItemStyleBordered
target:self
action:@selector(showInfo:)] autorelease];
L'utilisation de cet initialiseur génère un bouton de barre dont la cible et le sélecteur fonctionnent réellement. C’est aussi plus facile que d’emballer l’image dans une vue personnalisée, mais ce n’est que du glaçage.
Swift 3 : Voici ma mise en œuvre complète pour la personnalisation des boutons et la gestion des événements.
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton.init(type: .custom)
button.setTitle("Tester", for: .normal)
button.setTitleColor(.darkGray, for: .normal)
button.layer.borderWidth = 1
button.layer.cornerRadius = 5
button.layer.borderColor = UIColor.darkGray.cgColor
button.addTarget(self, action: #selector(self.handleButton), for: .touchUpInside)
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: button)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let button = self.navigationItem.rightBarButtonItem?.customView {
button.frame = CGRect(x:0, y:0, width:80, height:34)
}
}
func handleButton( sender : UIButton ) {
// It would be Nice is isEnabled worked...
sender.alpha = sender.alpha == 1.0 ? 0.5 : 1.0
}
J'espère que cela t'aides
Jacob, tout va bien, mais vous n'avez peut-être pas fourni le bon sélecteur.
Pouvez-vous vérifier que votre action est réellement déclarée
- (void) deselectAll;
et pas
- (void) deselectAll:(id)sender;
Si c'est le dernier cas, vous devrez définir l'action sur @selector(deselectAll:)
. (notez le point-virgule correspondant à la déclaration de la méthode)
De plus, void pourrait être IBAction
, mais ce n'est pas pertinent pour le problème que vous rencontrez.
Si vous ne souhaitez pas régler avec un UIImage et avoir une vue personnalisée dans votre élément barbutton, définissez un outil de reconnaissance des gestes tactiles sur la propriété customview de votre élément barbutton.
let tap = UITapGestureRecognizer(target: self, action: #selector(goProButtonPressed))
deviceStatusBarButtonItem.customView?.addGestureRecognizer(tap)
Swift 3. J'ai eu un problème similaire où j'avais une vue personnalisée à l'intérieur de l'élément de bouton de barre. Pour que le robinet fonctionne, j'ai affecté un geste à la vue et défini l'action. La vue devait être un point de vente à lui attribuer. Cela fonctionnait avec la vue personnalisée.
Définir le geste comme variable de classe
@IBOutlet weak var incidentView: UIView!
let incidentTap = UITapGestureRecognizer()
Dans viewDidLoad
incidentTap.addTarget(self, action: #selector(self.changeIncidentBarItem))
incidentView.addGestureRecognizer(incidentTap)
Votre vue personnalisée mange-t-elle des événements tactiles ou les transmet-elle à la vue parent?
Pour rendre ce travail facile, j'ai créé une catégorie sur UIBarButtonItem qui ressemble à ceci:
@implementation UIBarButtonItem (CustomButtonView)
- (void)setButtonImage:(UIImage *)image
{
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setBackgroundImage:image forState:UIControlStateNormal];
[button sizeToFit];
[button addTarget:self.target action:self.action forControlEvents:UIControlEventTouchUpInside];
self.customView = button;
}
- (UIImage *)buttonImage
{
return [(UIButton *)self.customView imageForState:UIControlStateNormal];
}
@end
Dans votre code client, utilisez simplement:
myBarButtonItem.buttonImage = [UIImage imagedNamed:@"image_name"];
Ainsi, vous pouvez toujours associer vos objectifs et vos actions dans IB (il est judicieux de placer autant de configurations d'interface utilisateur dans IB que vous le pouvez).