web-dev-qa-db-fra.com

Passage de paramètres sur l'action du bouton: @selector

Je souhaite transmettre l'URL du film de mon bouton généré dynamiquement à MediaPlayer:

[button addTarget:self action:@selector(buttonPressed:) withObject:[speakers_mp4 objectAtIndex:[indexPath row]] forControlEvents:UIControlEventTouchUpInside];

mais action:@selector() withObject: ne fonctionne pas?

N 'y a-t-il pas une autre solution?

Merci pour l'aide!

48
Pascal Bayer

Modifier. J'ai trouvé un chemin plus propre!

Un argument que le bouton peut recevoir est (id)sender. Cela signifie que vous pouvez créer un nouveau bouton, héritant de UIButton, qui vous permet de stocker les autres arguments souhaités. Espérons que ces deux extraits illustrent ce qu'il faut faire.

  myOwnbutton.argOne = someValue
  [myOwnbutton addTarget:self action:@selector(buttonTouchUpInside:) forControlEvents:UIControlEventTouchUpInside];

et

- (IBAction) buttonTouchUpInside:(id)sender {
  MyOwnButton *buttonClicked = (MyOwnButton *)sender; 
  //do as you please with buttonClicked.argOne
}

C'était ma suggestion initiale.

Il existe un moyen d'obtenir le même résultat, mais ce n'est pas joli. Supposons que vous souhaitiez ajouter un paramètre à votre méthode navigate. Le code ci-dessous ne vous permettra pas de transmettre ce paramètre à navigate

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

Pour contourner cela, vous pouvez déplacer la variable method dans une classe qui lui est propre et définir les "paramètres" comme attributs de cette classe ...

NavigationAid *navAid = [[NavigationAid alloc] init];
navAid.firstParam = someVariableOne
navAid.secondParam = someVariableTwo
[button addTarget:navAid action:@selector(navigate) forControlEvents:UIControlEventTouchUpInside];

Bien sûr, vous pouvez conserver la méthode de navigation dans la classe d'origine et la faire appeler par navAid, à condition qu'elle sache où la trouver.

NavigationAid *navAid = [[NavigationAid alloc] init];
navAid.whereToCallNavigate = self
navAid.firstParam = someVariableOne
navAid.secondParam = someVariableTwo
[button addTarget:navAid action:@selector(navigate) forControlEvents:UIControlEventTouchUpInside];

Comme je l'ai dit, ce n'est pas joli, mais cela a fonctionné pour moi et je n'ai trouvé personne qui suggère une autre solution efficace.

60
WoodenKitty

J'ai trouvé une solution. L'appel:

-(void) someMethod{
    UIButton * but;
    but.tag = 1;//some id button that you choice 
    [but addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside]; 
}

Et voici la méthode appelée:

-(void) buttonPressed : (id) sender{
    UIButton *clicked = (UIButton *) sender;
    NSLog(@"%d",clicked.tag);//Here you know which button has pressed
}
32
orafaelreis

J'ai fait une solution basée en partie sur les informations ci-dessus . Je viens de définir le titleLabel . text sur 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

12
Trausti Thor

Vous pouvez sous-classer un UIButton nommé MyButton et transmettre le paramètre en fonction des propriétés de MyButton.

Ensuite, récupérez le paramètre auprès de l'expéditeur (id). 

11
AechoLiu

Ajouter le titleLabel masqué au paramètre est la meilleure solution.

J'ai généré un tableau arrUrl qui stocke le NSURL des fichiers mov de mon album téléphonique en énumérant le bloc d’actifs.

Après cela, je saisis Frame, disons, récupère l'image à 3:00 secondes dans le fichier vidéo et génère le fichier image à partir de l'image. 

Ensuite, passez en boucle sur l’arrUR et utilisez le programme pour générer le bouton avec une image dans le bouton, ajoutez le bouton à la sous-vue de la self.view.

Parce que je dois passer l’URL du film à la fonction playMovie, je dois attribuer le button.titleLabel.text à une URL du film. et la fonction des événements de bouton, récupérez l’URL du fichier buttontitleLable.txt.

-(void)listVideos

{
   for(index=0;index<[self.arrUrl count];index++{
      UIButton *imageButton = [UIButton buttonWithType:UIButtonTypeCustom];
      imageButton.frame = CGRectMake(20,50+60*index,50,50);

      NSURL *dUrl = [self.arrUrl objectAtIndex:index];

      [imageButton setImage:[[UIImage allow] initWithCGImage:*[self getFrameFromeVideo:dUrl]] forState:UIControlStateNormal];
      [imageButton addTarget:self action:@selector(playMovie:) forControlEvents:UIControlEventTouchUpInside];
      imageButton.titleLabel.text = [NSString strinfWithFormat:@"%@",dUrl];
      imageButton.titleLabel.hidden = YES;

      [self.view addSubView:imageButton];
   }
}

-(void)playMovie:(id) sender{
   UIButton *btn = (UIButton *)sender;
   NSURL *movUrl = [NSURL URLWithString:btn.titleLabel.text];
   moviePlayer = [[MPMoviePlayerViewController alloc] initWithContentURL:movUrl];
   [self presentMoviePlayerViewControllerAnimated:moviePlayer];
}

-(CGIImageRef *)getFrameFromVideo:(NSURL *)mUrl{
   AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:mUrl option:nil];
   AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
   generator.appliesPreferredTrackTransform = YES;
   NSError *error =nil;
   CMTime = CMTimeMake(3,1);
   CGImageRef imageRef = [generator copyCGImageAtTime:time actualTime:nil error:&error];
   if(error !=nil) {
      NSLog(@"%@",sekf,error);
   }

   return @imageRef;
}
3
showmyroutes

tl; dr: utiliser des blocs

Pour Obj-C, par exemple, il existe un CocoaPod SHControlBlocks , dont l'utilisation serait:

[self.btnFirst SH_addControlEvents:UIControlEventTouchDown withBlock:^(UIControl *sender) {
    [weakSelf performSegueWithIdentifier:@"second" sender:nil];
    NSLog(@"first");
  }];

Pour Swift, j'aime beaucoup le pod Actions , qui autorise les blocs pour UIControls [1]:

// UIControl
let button = UIButton()
button.add(event: .touchUpInside) {
    print("Button tapped")
    playMusic(from: speakers_mp4, withSongAtPosition: indexPath.row)
}

Pas que quiconque lit un fil de 3 ans. :: grillons ::

[1] Et UIView, UITextField, UIGestureRecognizer, UIBarButtonItem, Timer (anciennement NSTimer) et NotificationCenter (anciennement NSNotificationCenter).

1
AmitaiB

Je pense que la bonne méthode devrait être: - (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents

Référence UIControl

Où trouvez-vous votre méthode?

Je vois que votre sélecteur a un argument, cet argument sera rempli par le système d’exécution. Il vous renverra le bouton à travers cet argument.

Votre méthode devrait ressembler à:

- (void)buttonPressed:(id)BUTTON_HERE { }

1
vodkhang

Vous pouvez définir la balise du bouton et y accéder depuis l'expéditeur en action

[btnHome addTarget:self action:@selector(btnMenuClicked:)     forControlEvents:UIControlEventTouchUpInside];
                    btnHome.userInteractionEnabled = YES;
                    btnHome.tag = 123;

Dans la fonction appelée

-(void)btnMenuClicked:(id)sender
{
[sender tag];

    if ([sender tag] == 123) {
        // Do Anything
    }
}
1
Fawad Masud

Pour ajouter à la réponse de Tristan , le bouton peut également recevoir (id)event en plus de (id)sender:

- (IBAction) buttonTouchUpInside:(id)sender forEvent:(id)event { .... }

Cela peut être utile si, par exemple, le bouton est dans une cellule de UITableView et que vous voulez trouver le indexPath du bouton qui a été touché (bien que je suppose que cela peut également être trouvé via sender element).

0
newenglander

J'ai une autre solution dans certains cas.

stockez votre paramètre dans un UILabel caché. Ajoutez ensuite UILabel en tant que sous-vue de UIButton.

lorsque le bouton est cliqué, nous pouvons vérifier toutes les sous-vues d'UIButton. normalement seulement 2 UILabel dedans.

l'un est le titre de UIButton, l'autre est celui que vous venez d'ajouter. Si vous lisez la propriété de texte de UILabel, vous obtiendrez le paramètre. 

Ceci s'applique uniquement au paramètre de texte.

0
LetBulletFlies

UIButton répond à addTarget: action: forControlEvents: puisqu'il hérite de UIControl. Mais il ne répond pas à addTarget: action: withObject: forControlEvents:

voir référence pour la méthode et pour UIButton

Vous pourriez étendre UIButton avec une catégorie pour implémenter cette méthode, pensa-t-on.

0
Daniel