Appuie long sur un button

al33eral33er Membre
10:30 modifié dans API UIKit #1
Bonjour,

J'ai une vue avec quatre bouton. Dans cette vue il y aussi un textField me permettant de rentrer un string.

Tous les boutons sont programmés pour agir lorsque l'on touchup inside.

Je souhaiterais leur rajouter une fonctionnalité. Quand on fait un appuie long (deux seconde par exemple) sur un des boutons,  je voudrais que le title du bouton soit modifié par le .text du textfield. 

Merci pour votre aide.

Alexandre.

Réponses

  • Philippe49Philippe49 Membre
    10:30 modifié #2
    J'essaierais de connecter le bouton avec touch down + touch up, en mesurant le temps entre le touch down et le touch up entre les deux événements .

  • al33eral33er Membre
    10:30 modifié #3
    Merci Philippe.
  • AliGatorAliGator Membre, Modérateur
    10:30 modifié #4
    Sinon j'ai déjà  fait ça dans une appli, si tu veux que par exemple quand tu fais un touchDown, si tu laisses appuyé 2 secondes ça fasse une action donnée... sans attendre le touchUp (qui pourrait, lui, par exemple, intervenir 5 ou 10 secondes après on sait pas), il suffit de :

    - lancer un timer dans le touchDown, d'une durée de 2 secondes, et avec comme action le @selector qui va exécuter ton code à  faire lors d'un appui long
    - et dans le touchUp, tu invalides ce timer

    Comme ça si tu fais un appui de moins de 2 secondes le timer va se lancer mais va pas avoir le temps de se terminer car tu auras fait un touchUp avant les 2 secondes donc ça l'aura invalidé. Et sinon si u fais un touchDown de plus de 2 secondes, au bout de 2 secondes le code de ton appui long va s'exécuter, sans attendre le touchUp.
  • al33eral33er Membre
    10:30 modifié #5
    et si cela ne depasse pas deux secondes, il garde le touch up inside ?
  • AliGatorAliGator Membre, Modérateur
    février 2009 modifié #6
    Oui tout à  fait. En fait avec ma méthode, dans tous les cas le touchUpInside est appelé, que tu arrête ton appui avant ou après les 2 secondes.
    Et dans la méthode où tu enlèves ton appui (touchUpInside donc), tu invalides ton NSTimer, donc :
    - soit tu arrives là  avant les 2 secondes et donc ça "annule" le timer donc la méthode pour l'appui long ne sera finalement pas appelée...
    - soit tu arrives dans cette méthode après les 2 secondes (et donc la méthode pour l'appui long aura eu le temps d'être appelée par le NSTimer entre temps)...
    Mais dans tous les cas tu peux continuer d'exécuter du code dans ta méthode de touchUp.

    Moi j'ai implémenté ça dans une UIView avec les méthodes de NSResponder touchBegan/touchEnded : j'ai une variable d'instance [tt]NSTimer* longTouchTimer[/tt] dans le .h de ma classe, et en gros mon code ressemble à  :
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event<br />{<br />	longTouchTimer = [NSTimer scheduledTimerWithTimeInterval:2. target:self<br />			selector:@selector(longTouchAction:) userInfo:nil repeats:NO];<br /><br />	// ici si tu mets d&#39;autre code ça sera exécuté dès le début du touchDown<br />	// sans attendre les 2 secondes. Moi je n&#39;ai pas eu l&#39;utilité de rajouter de truc pour mon cas<br />	// mais je sais pas si toi tu veux un comportement supplémentaire ici<br />}<br /><br />- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event<br />{<br />	if ([longTouchTimer isValid])<br />	{<br />		// le &quot;touchUp&quot; est intervenu avant les 2 secondes<br />		// (le NSTimer est encore valide donc il a pas eu le temps de se déclencher<br />		// du coup on annule le timer pour éviter le déclenchement de -(void)longTouchAction<br />		[longTouchTimer invalidate];<br />		longTouchTimer = nil;<br /><br />		// ici on peut mettre du code qui ne sera exécuté que si le touchUp est intervenu après un appui court<br />	} else {<br />		// ici on peut mettre du code qui ne sera exécuté que si le touchUp est intervenu après un appui long<br />	}<br />	// ici on peut mettre du code qui sera exécuté que le touchUp soit intervenue après un appui court ou long<br />}<br /><br />- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event<br />{<br />	[longTouchTimer invalidate];<br />	longTouchTimer = nil;<br />}<br /><br />-(void) longTouchAction:(NSTimer*)timer<br />{<br />	// code à  exécuter suite à  un appui long.<br /><br />	// Ce code sera exécuté 2 secondes après un touchBegin (touchDown)<br />	// sauf si entre temps il y a eu un touchEnded (touchUp avant les 2 secondes quoi)<br /><br />	longTouchTimer = nil;<br />}
    
  • Philippe49Philippe49 Membre
    10:30 modifié #7
    Aligator is cunning as a fox 
  • al33eral33er Membre
    10:30 modifié #8
    Merci Ali. Je vais essayer.

    Alexandre.
  • AliGatorAliGator Membre, Modérateur
    février 2009 modifié #9
    Arf bah merci Philippe mais il est peut-être pas si rusé que ça l'AliGator, car j'ai pensé après que plutôt que d'utiliser un NSTimer en variable d'instance, j'aurais mieux fait tout simplement d'appeler les méthodes un peut faites pour ça (et qui gèrent un timer en interne)... :

    - [tt][self performSelector:@selector(longTouchAction:) withObject:nil afterDelay:2.0];[/tt] dans "touchBegan"
    - [tt][NSObject cancelPreviousPerformRequestsWithTarget:self];[/tt] dans le touchEnded (et le touchCancelled)

    Bon c'est vrai que là  on ne peut plus tester si le timer a été exécuté (isValid) ou pas du coup puisqu'on n'y a plus accès directement... mais ça reste sans doute quand même plus propre. Et si on veut tester pour savoir s'il y a eu un appui long de fait ou pas, je trouve plus propre de faire comme ça et de rajouter une variable booléenne [tt]BOOL longTouch[/tt] qu'on passe à  NO dans [tt]touchBegan[/tt], et à  YES dans [tt]longTouchAction[/tt] comme ça dans [tt]touchEnded[/tt] on peut savoir si y'a eu un longTouch ou pas ;)
  • Philippe49Philippe49 Membre
    juillet 2009 modifié #10
    Mon idée c'était plutôt cela:
    On fait une double connection du bouton pour Touch Down et Touch Up Inside sans jouer sur le touchBegan && touchEnded

    <br />@private<br />NSDate * downDate; // variable d&#39;instance<br />#define TOUCHDELAY 2.<br /><br />-(IBAction) longTouchAction:(id) sender {<br />	static BOOL touchDown=YES;		// En cas de plusieurs view controllers, mettre en variable d&#39;instance<br />	NSLog(@&quot;&#092;n *********** touchDown =%d&#092;n ***********  downDate= %@&quot;,touchDown,downDate);<br />	if(touchDown) {<br />		[downDate release];<br />		downDate=[[NSDate date] retain];<br />		touchDown=NO;<br />	} else 	{<br />		NSDate * upDate=[NSDate date];<br />		NSLog(@&quot;&#092;n *********** touchDown =%d&#092;n ***********  downDate= %@&#092;n ***********  upDate= %@&quot;,touchDown,downDate,upDate);<br />		if( [upDate timeIntervalSinceDate:downDate] &gt; TOUCHDELAY ) {<br />			NSLog(@&quot;action&quot;);<br />			// 	....		<br />		}	<br />		// et mise à  jour de touchDown selon les cas<br />	}<br />}
    


    (avec le downDate qui reste à  désallouer à  la fermeture du view controller, il faut sans doute mieux le mettre en variable d'instance @private)
  • al33eral33er Membre
    10:30 modifié #11
    Merci à  tous les deux.

    J'ai utilisé la première méthode d'ali et ça fonctionne super.

    Alexandre.
Connectez-vous ou Inscrivez-vous pour répondre.