158 votes

iPhone : détection des temps d’inactivité/inactivité utilisateur depuis le dernier tactile écran

Personne n'a mis en œuvre une fonctionnalité où, si l'utilisateur n'a pas touché l'écran pendant un certain temps, vous prenez un certain type d'action? Je suis à essayer de comprendre la meilleure façon de le faire.

Il y a un peu liés à la méthode dans UIApplication:

[UIApplication sharedApplication].idleTimerDisabled;

Il serait bien si vous avait plutôt quelque chose comme ceci:

NSTimeInterval timeElapsed = [UIApplication sharedApplication].idleTimeElapsed;

Ensuite, j'ai pu configurer un minuteur et vérifier périodiquement cette valeur, et de prendre un peu d'action quand il dépasse un certain seuil.

J'espère que ça explique ce que je cherche. Quelqu'un a abordé cette question déjà, ou avez des pensées sur la façon dont vous le feriez? Merci.

158voto

Mike McMaster Points 4300

Voici la réponse que je cherchais:

Demandez à votre application de déléguer la sous-classe UIApplication. Dans le fichier d'implémentation, remplacez la méthode sendEvent:

 - (void)sendEvent:(UIEvent *)event {
    [super sendEvent:event];

    // Only want to reset the timer on a Began touch or an Ended touch, to reduce the number of timer resets.
    NSSet *allTouches = [event allTouches];
    if ([allTouches count] > 0) {
        // allTouches count only ever seems to be 1, so anyObject works here.
        UITouchPhase phase = ((UITouch *)[allTouches anyObject]).phase;
        if (phase == UITouchPhaseBegan || phase == UITouchPhaseEnded)
            [self resetIdleTimer];
    }
}

- (void)resetIdleTimer {
    if (idleTimer) {
        [idleTimer invalidate];
        [idleTimer release];
    }

    idleTimer = [[NSTimer scheduledTimerWithTimeInterval:maxIdleTime target:self selector:@selector(idleTimerExceeded) userInfo:nil repeats:NO] retain];
}

- (void)idleTimerExceeded {
    NSLog(@"idle time exceeded");
}
 

où maxIdleTime et idleTimer sont des variables d'instance.

Pour que cela fonctionne, vous devez également modifier votre main.m pour indiquer à UIApplicationMain d'utiliser votre classe de délégué (dans cet exemple, AppDelegate) en tant que classe principale:

 int retVal = UIApplicationMain(argc, argv, @"AppDelegate", @"AppDelegate");
 

90voto

Chris Miles Points 2504

J'ai une variation du minuteur d'inactivité solution qui ne nécessite pas de sous-classement UIApplication. Il fonctionne sur une sous-classe UIViewController, est utile si vous avez seulement une-vue-contrôleur (comme une application interactive ou jeu) ou ne voulez gérer délai d'inactivité dans une vue spécifique du contrôleur.

Il a également de ne pas re-créer le NSTimer objet chaque fois que le minuteur d'inactivité est réinitialisé. Il ne crée un nouveau si la minuterie se déclenche.

Votre code peut appeler resetIdleTimer pour tous les autres événements qui peuvent avoir besoin d'invalider le minuteur d'inactivité (comme significatif de l'accéléromètre de l'entrée).

@interface MainViewController : UIViewController
{
    NSTimer *idleTimer;
}
@end

#define kMaxIdleTimeSeconds 60.0

@implementation MainViewController

#pragma mark -
#pragma mark Handling idle timeout

- (void)resetIdleTimer {
    if (!idleTimer) {
        idleTimer = [[NSTimer scheduledTimerWithTimeInterval:kMaxIdleTimeSeconds
                                                      target:self
                                                    selector:@selector(idleTimerExceeded)
                                                    userInfo:nil
                                                     repeats:NO] retain];
    }
    else {
        if (fabs([idleTimer.fireDate timeIntervalSinceNow]) < kMaxIdleTimeSeconds-1.0) {
            [idleTimer setFireDate:[NSDate dateWithTimeIntervalSinceNow:kMaxIdleTimeSeconds]];
        }
    }
}

- (void)idleTimerExceeded {
    [idleTimer release]; idleTimer = nil;
    [self startScreenSaverOrSomethingInteresting];
    [self resetIdleTimer];
}

- (UIResponder *)nextResponder {
    [self resetIdleTimer];
    return [super nextResponder];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    [self resetIdleTimer];
}

@end

(nettoyage de la mémoire code exclus pour des raisons de concision.)

12voto

Brian King Points 1461

Ce fil a été d'une grande aide, et je l'ai enveloppé dans un UIWindow sous-classe qui envoie des notifications. J'ai choisi des notifications pour en faire un véritable couplage lâche, mais vous pouvez ajouter un délégué assez facilement.

Voici l'essentiel:

http://gist.github.com/365998

Aussi, la raison de la UIApplication sous-classe problème est que la POINTE est de l'installation pour ensuite créer 2 UIApplication objets, car il contient l'application et le délégué. UIWindow sous-classe fonctionne très bien.

5voto

Roby Points 41

En fait, l'idée de sous-classement fonctionne très bien. Ne faites simplement pas de votre délégué la sous-classe UIApplication. Créez un autre fichier qui hérite de UIApplication (par exemple, myApp) dans IB définissez la classe de l'objet fileOwner sur myApp, dans myApp.m implémentez la méthode sendEvent comme ci-dessus, dans main.m: int retVal = UIApplicationMain (argc, argv, @ " myApp.m ", @" myApp.m ") au tour est joué

4voto

Kay Points 6742

Je viens de tomber sur ce problème avec un jeu qui est contrôlé par les mouvements c'est à dire a l'écran de verrouillage désactivé, mais devrait permettre de nouveau en mode menu. Au lieu d'un timer je encapsulé tous les appels d' setIdleTimerDisabled dans une petite classe fournissant des méthodes suivantes:

- (void) enableIdleTimerDelayed {
    [self performSelector:@selector (enableIdleTimer) withObject:nil afterDelay:60];
}

- (void) enableIdleTimer {
    [NSObject cancelPreviousPerformRequestsWithTarget:self];
    [[UIApplication sharedApplication] setIdleTimerDisabled:NO];
}

- (void) disableIdleTimer {
    [NSObject cancelPreviousPerformRequestsWithTarget:self];
    [[UIApplication sharedApplication] setIdleTimerDisabled:YES];
}

disableIdleTimer désactive minuteur d'inactivité, enableIdleTimerDelayed lors de la saisie du menu ou quoi que doit s'exécuter avec minuteur d'inactivité de l'actif et enableIdleTimer est appelé à partir de votre AppDelegate de l' applicationWillResignActive méthode pour s'assurer que toutes vos modifications sont réinitialisé correctement pour que le système le comportement par défaut.
J'ai écrit un article et a fourni le code de la classe singleton IdleTimerManager Minuteur d'Inactivité de la Manutention dans les Jeux iPhone

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X