J'utilise addTarget: action: forControlEvents comme ceci:
[newsButton addTarget:self
action:@selector(switchToNewsDetails)
forControlEvents:UIControlEventTouchUpInside];
et je voudrais passer des paramètres à mon sélecteur "switchToNewsDetails". La seule chose que j'ai réussi à faire est de transmettre l'expéditeur (id) en écrivant:
action:@selector(switchToNewsDetails:)
Mais j'essaie de transmettre des variables telles que des valeurs entières. L'écrire de cette façon ne fonctionne pas:
int i = 0;
[newsButton addTarget:self
action:@selector(switchToNewsDetails:i)
forControlEvents:UIControlEventTouchUpInside];
L'écrire de cette façon ne fonctionne pas non plus:
int i = 0;
[newsButton addTarget:self
action:@selector(switchToNewsDetails:i:)
forControlEvents:UIControlEventTouchUpInside];
Toute aide serait appréciée :)
action:@selector(switchToNewsDetails:)
Vous ne transmettez pas de paramètres à la méthode switchToNewsDetails:
ici. Vous venez de créer un sélecteur pour faire en sorte que le bouton puisse l’appeler lorsque certaines actions se produisent (retouches dans votre cas). Les contrôles peuvent utiliser 3 types de sélecteurs pour répondre aux actions. Tous ont une signification prédéfinie pour leurs paramètres:
sans paramètres
action:@selector(switchToNewsDetails)
avec 1 paramètre indiquant le contrôle qui envoie le message
action:@selector(switchToNewsDetails:)
Avec 2 paramètres indiquant le contrôle qui envoie le message et l'événement qui a déclenché le message:
action:@selector(switchToNewsDetails:event:)
Vous ne savez pas exactement ce que vous essayez de faire, mais si vous souhaitez attribuer un index de détails spécifique à chaque bouton, vous pouvez procéder comme suit:
dans la méthode switchToNewsDetails:
, vous pouvez obtenir cet index et ouvrir les détails appropriés:
- (void)switchToNewsDetails:(UIButton*)sender{
[self openDetails:sender.tag];
// Or place opening logic right here
}
Pour transmettre des paramètres personnalisés avec le clic du bouton, il vous suffit de SUBCLASS UIButton.
(ASR est activé, donc il n'y a pas de version dans le code.)
C'est myButton.h
#import <UIKit/UIKit.h>
@interface myButton : UIButton {
id userData;
}
@property (nonatomic, readwrite, retain) id userData;
@end
C'est myButton.m
#import "myButton.h"
@implementation myButton
@synthesize userData;
@end
Usage:
myButton *bt = [myButton buttonWithType:UIButtonTypeCustom];
[bt setFrame:CGRectMake(0,0, 100, 100)];
[bt setExclusiveTouch:NO];
[bt setUserData:**(insert user data here)**];
[bt addTarget:self action:@selector(touchUpHandler:) forControlEvents:UIControlEventTouchUpInside];
[view addSubview:bt];
Fonction de réception:
- (void) touchUpHandler:(myButton *)sender {
id userData = sender.userData;
}
Si vous avez besoin de moi pour être plus spécifique sur une partie du code ci-dessus - n'hésitez pas à poser des questions dessus.
Target-Action permet de sélectionner trois formes d’action:
- (void)action
- (void)action:(id)sender
- (void)action:(id)sender forEvent:(UIEvent *)event
Vous pouvez transmettre les données de votre choix via l'objet bouton lui-même (en accédant à CALayers keyValue dict).
Définissez votre cible comme ceci (avec le ":")
[myButton addTarget:self action:@selector(buttonTap:) forControlEvents:UIControlEventTouchUpInside];
Ajoutez vos données au bouton lui-même (ainsi le .layer
du bouton qui se trouve) comme ceci:
NSString *dataIWantToPass = @"this is my data";//can be anything, doesn't have to be NSString
[myButton.layer setValue:dataIWantToPass forKey:@"anyKey"];//you can set as many of these as you'd like too!
Ensuite, lorsque vous appuyez sur le bouton, vous pouvez le vérifier comme suit:
-(void)buttonTap:(UIButton*)sender{
NSString *dataThatWasPassed = (NSString *)[sender.layer valueForKey:@"anyKey"];
NSLog(@"My passed-thru data was: %@", dataThatWasPassed);
}
J'ai fait une solution basée en partie par les informations ci-dessus. Je viens de définir le titlelabel.text à la chaîne que je veux passer, et définir le titlelabel.hidden = YES
Comme ça :
UIButton *imageclick = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
imageclick.frame = photoframe;
imageclick.titleLabel.text = [NSString stringWithFormat:@"%@.%@", ti.mediaImage, ti.mediaExtension];
imageclick.titleLabel.hidden = YES;
De cette façon, il n'y a pas besoin d'un héritage ou d'une catégorie et il n'y a pas de fuite de mémoire
Je créais plusieurs boutons pour chaque numéro de téléphone dans un tableau, de sorte que chaque bouton devait appeler un numéro de téléphone différent. J'ai utilisé la fonction setTag car je créais plusieurs boutons dans une boucle for:
for (NSInteger i = 0; i < _phoneNumbers.count; i++) {
UIButton *phoneButton = [[UIButton alloc] initWithFrame:someFrame];
[phoneButton setTitle:_phoneNumbers[i] forState:UIControlStateNormal];
[phoneButton setTag:i];
[phoneButton addTarget:self
action:@selector(call:)
forControlEvents:UIControlEventTouchUpInside];
}
Ensuite, dans ma méthode call: j'ai utilisé la même chose pour loop et une instruction if pour choisir le numéro de téléphone correct:
- (void)call:(UIButton *)sender
{
for (NSInteger i = 0; i < _phoneNumbers.count; i++) {
if (sender.tag == i) {
NSString *callString = [NSString stringWithFormat:@"telprompt://%@", _phoneNumbers[i]];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:callString]];
}
}
}
Il existe un autre moyen d’obtenir indexPath de la cellule où le bouton a été enfoncé:
en utilisant le sélecteur d’action habituel comme:
UIButton *btn = ....;
[btn addTarget:self action:@selector(yourFunction:) forControlEvents:UIControlEventTouchUpInside];
puis dans votre fonction:
- (void) yourFunction:(id)sender {
UIButton *button = sender;
CGPoint center = button.center;
CGPoint rootViewPoint = [button.superview convertPoint:center toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:rootViewPoint];
//the rest of your code goes here
..
}
puisque vous obtenez un indexPath, il est devenu beaucoup plus simple.
Comme il existe de nombreuses façons mentionnées ici pour la solution, fonctionnalité catégorie sauf.
Utilisez la fonctionnalité category pour étendre un élément défini (intégré) dans votre élément personnalisable.
Par exemple (ex):
@interface UIButton (myData)
@property (strong, nonatomic) id btnData;
@end
dans votre vue Controller.m
#import "UIButton+myAppLists.h"
UIButton *myButton = // btn intialisation....
[myButton set btnData:@"my own Data"];
[myButton addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
Gestionnaire d'événements:
-(void)buttonClicked : (UIButton*)sender{
NSLog(@"my Data %@", sender. btnData);
}
Cela a résolu mon problème mais il s'est écrasé à moins que je ne change
action:@selector(switchToNewsDetails:event:)
à
action:@selector(switchToNewsDetails: forEvent:)
Voir mon commentaire ci-dessus, et je crois que vous devez utiliser NSInvocation quand il y a plus d'un paramètre
plus d'informations sur NSInvocation ici
http://cocoawithlove.com/2008/03/construct-nsinvocation-for-any-message.html
Vous pouvez remplacer action-cible par une fermeture (bloc dans Objective-C) en ajoutant un wrapper de fermeture d'assistance (ClosureSleeve) et en l'ajoutant en tant qu'objet associé au contrôle pour le conserver. De cette façon, vous pouvez passer tous les paramètres.
class ClosureSleeve {
let closure: () -> ()
init(attachTo: AnyObject, closure: @escaping () -> ()) {
self.closure = closure
objc_setAssociatedObject(attachTo, "[\(arc4random())]", self, .OBJC_ASSOCIATION_RETAIN)
}
@objc func invoke() {
closure()
}
}
extension UIControl {
func addAction(for controlEvents: UIControlEvents, action: @escaping () -> ()) {
let sleeve = ClosureSleeve(attachTo: self, closure: action)
addTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: controlEvents)
}
}
Usage:
button.addAction(for: .touchUpInside) {
self.switchToNewsDetails(parameter: i)
}
Si vous souhaitez simplement modifier le texte du leftBarButtonItem indiqué par le contrôleur de navigation en même temps que la nouvelle vue, vous pouvez modifier le titre de la vue actuelle juste avant d'appeler pushViewController avec le texte souhaité et le restaurer dans le rappel viewHasDisappered pour les futures représentations de la vue en cours.
Cette approche conserve la fonctionnalité (popViewController) et l'apparence de la flèche affichée.
Cela fonctionne pour nous au moins avec iOS 12, construit avec Xcode 10.1 ...
J'ai sous-classé UIButton dans CustomButton et j'ajoute une propriété dans laquelle je stocke mes données. J'appelle donc l'expéditeur de la méthode: (CustomButton *) et dans la méthode, je ne lis que mes données sender.myproperty.
Exemple de bouton personnalisé:
@interface CustomButton : UIButton
@property(nonatomic, retain) NSString *textShare;
@end
Action de la méthode:
+ (void) share: (CustomButton*) sender
{
NSString *text = sender.textShare;
//your work…
}
Attribuer une action
CustomButton *btn = [[CustomButton alloc] initWithFrame: CGRectMake(margin, margin, 60, 60)];
// other setup…
btnWa.textShare = @"my text";
[btn addTarget: self action: @selector(shareWhatsapp:) forControlEvents: UIControlEventTouchUpInside];