J'ai le code suivant:
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewAnimationCurveEaseOut | UIViewAnimationOptionAllowUserInteraction
animations:^{
CGRect r = [btn frame];
r.Origin.y -= 40;
[btn setFrame: r];
}
completion:^(BOOL done){
if(done){
[UIView animateWithDuration:0.3
delay:1
options:UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionAllowUserInteraction
animations:^{
CGRect r = [btn frame];
r.Origin.y += 40;
[btn setFrame: r];
}
completion:^(BOOL done){if(done) zombiePopping = 0; }];
}
}];
Le problème est qu'il semble que le bouton ne réagisse pas tant qu'il est animé, même si j'utilise UIViewAnimationOptionAllowInteraction
, ce qui est un peu étrange pour moi.
Peut-être que cela sera le plus possible avec Core Animation pour fonctionner? et si oui, comment pourrais-je m'y prendre?
La partie tactile du bouton ne coïncide pas avec le cadre visible du bouton lorsqu'il est animé.
En interne, l'image du bouton sera définie sur la valeur finale de votre animation. Vous devriez trouver que vous pouvez taper dans cette zone et cela fonctionnerait.
Pour appuyer sur un bouton en mouvement, vous devez effectuer un test de frappe sur la propriété .layer.presentationLayer
du bouton (vous devez importer le framework QuartzCore pour ce faire). Cela se fait généralement de manière tactile dans votre contrôleur de vue.
Je suis heureux de développer cette réponse si vous avez besoin de plus.
Voici comment vous répondriez à un événement tactile en testant les couches de présentation. Ce code se trouve dans la sous-classe du contrôleur de vue qui gère vos boutons. Lorsque j’ai fait cela, j’ai été intéressé par le toucher initial plutôt que par le toucher (ce qui est typiquement le moment où un tap serait enregistré), mais le principe est le même.
N'oubliez pas d'importer le cadre QuartzCore et de l'ajouter à votre projet.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
for (UIButton *button in self.buttonsOutletCollection)
{
if ([button.layer.presentationLayer hitTest:touchLocation])
{
// This button was hit whilst moving - do something with it here
break;
}
}
}
Dans mon cas, j’ai mis superView.alpha = 0
, il arrête l’interaction du bouton bien que j’ai configuréUIViewAnimationOptionAllowUserInteraction
.
Solution? Facile, il suffit de réduire alpha
à 0.1 au lieu de 0
[UIView animateWithDuration:durationTime delay:0 options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionOverrideInheritedOptions | UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse animations: ^{
superView.alpha = 0.1; // 0.0 will make the button unavailable to touch
} completion:nil];
L'ordre des options est important, vous devez d'abord placer UIViewAnimationOptionAllowUserInteraction
, puis ajouter d'autres options.
Dans Swift 3, utilisez: .allowUserInteraction
J'ai réalisé ceci en utilisant NSTimer: D'abord, lancez l'animation de démarrage, ensuite vous devriez lancer une minuterie, c'est le code de démonstration:
-(void)fun···
{
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewAnimationCurveEaseOut | UIViewAnimationOptionAllowUserInteraction
animations:^{
CGRect r = [btn frame];
r.Origin.y -= 40;
[btn setFrame: r];
}
completion:^(BOOL done){}];
then , you should start an timer,example:
//start timer
if (timer != nil)
{
[timer invalidate];
timer = nil;
}
[self performSelector:@selector(closeButton) withObject:nil afterDelay:0];
}
- (void)closeButton
{
if (timer != nil)
{
return;
}
//start timer
timer = [NSTimer scheduledTimerWithTimeInterval:1.5f target:self selector:@selector(timerEvent) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
- (void)timerEvent
{
[UIView animateWithDuration:0.3
delay:1
options:UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionAllowUserInteraction
animations:^{
CGRect r = [btn frame];
r.Origin.y += 40;
[btn setFrame: r];
}
completion:^(BOOL done){if(done) zombiePopping = 0; }];
[timer invalidate];
timer = nil;
}
Même réponse dans Swift (2.0), pour les paresseux. Remplacez-le par une collection de boucles et de sorties si nécessaire:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let touchLocation = touch!.locationInView(self.view)
if self.button.layer.presentationLayer()!.hitTest(touchLocation) != nil {
action() // Your action, preferably the original button action.
}
}
Swift 3.0 Créez un aperçu en haut dans viewdidload
let superView = UIView(frame: view.frame)
superView.isUserInteractionEnabled = true
superView.backgroundColor = UIColor.clear
superView.alpha = 0.1
view.addSubview(superView)
maintenant mettre en œuvre touchesbagan comme ça
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = (touches as NSSet).anyObject() as? UITouch else {
return
}
let touchLocation = touch.location(in: self.view)
if btnone.layer.presentation()?.hitTest(touchLocation) != nil {
print("1") // Do stuff for button
}
if btntwo.layer.presentation()?.hitTest(touchLocation) != nil {
print("2") // Do stuff
}
if btnthree.layer.presentation()?.hitTest(touchLocation) != nil {
print(3) // Do stuff
}
if btnfour.layer.presentation()?.hitTest(touchLocation) != nil {
print(4) // Do stuff
}
}
Version Swift: '999' est la valeur de tag utilisée pour identifier la vue cible.
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let touchLocation = (touch?.locationInView(self.rootView))!
for view in self.view.subviews {
if let layer = view.layer.presentationLayer()?.hitTest(touchLocation) where view.tag == 999 {
// Here view is the tapped view
print(view)
}
}
}
fonctionne comme un charme
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
if bounds.contains(point) && !hidden && userInteractionEnabled && enabled {
return self
}
return super.hitTest(point, withEvent: event)
}
Bien que ceci la réponse soit également correcte