Comment détecter toutes les touches dans Swift 2


4

J'essaie de créer une fonction de délai pour une application que je développe en utilisant Swift 2 mais dans swift 2, vous pouvez mettre ce code dans le délégué de l'application et cela fonctionne mais il le fait ne pas détecter toutes les presses du clavier, appuyer sur des boutons, des presses à textfield, et etc:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { 
    super.touchesBegan(touches, withEvent: event); 
    let allTouches = event!.allTouches(); 

    if(allTouches?.count > 0) { 
     let phase = (allTouches!.first as UITouch!).phase; 
     if(phase == UITouchPhase.Began || phase == UITouchPhase.Ended) { 
      //Stuff 
      timeoutModel.actionPerformed(); 
     } 
    } 
} 

Avant rapidement 2, je suis en mesure d'avoir la sous-classe AppDelegate UIApplication et passer outre sendEvent: comme ceci:

-(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) 
      [[InactivityModel instance] actionPerformed]; 
    } 
} 

le le code ci-dessus fonctionne pour chaque touche, mais l'équivalent rapide ne fonctionne que si une vue n'expire pas Est-ce que c'est au-dessus de cette hiérarchie d'UIWindow?

Est-ce que quelqu'un connaît un moyen de détecter chaque touche dans l'application?

  0

Cela a quelque chose à voir avec iOS 9 au lieu de Swift 2. J'ai une solution similaire dans mon UIWindow personnalisé et ça arrête de fonctionner aussi. Probablement en raison de la nouvelle vue de l'application iOS 9 split, etc. Donc, ils l'ont refait pour soutenir ces nouvelles fonctionnalités - deux applications ouvertes, clavier, ... Pas sûr à 100%, penser à haute voix ... 28 juil.. 152015-07-28 09:46:08

12

Comme je l'ai quelque chose de semblable dans ma demande, je viens d'essayer de le corriger:

  • override sendEvent dans UIWindow - ne fonctionne pas
  • override sendEvent déléguer - ne fonctionne pas

La seule façon est donc de fournir une sous-classe personnalisée UIApplication. Mon code à ce jour (fonctionne sur iOS 9) est:

@objc(MyApplication) class MyApplication: UIApplication { 

    override func sendEvent(event: UIEvent) { 
    // 
    // Ignore .Motion and .RemoteControl event 
    // simply everything else then .Touches 
    // 
    if event.type != .Touches { 
     super.sendEvent(event) 
     return 
    } 

    // 
    // .Touches only 
    // 
    var restartTimer = true 

    if let touches = event.allTouches() { 
     // 
     // At least one touch in progress? 
     // Do not restart auto lock timer, just invalidate it 
     // 
     for touch in touches.enumerate() { 
     if touch.element.phase != .Cancelled && touch.element.phase != .Ended { 
      restartTimer = false 
      break 
     } 
     } 
    } 

    if restartTimer { 
     // Touches ended || cancelled, restart auto lock timer 
     print("Restart auto lock timer") 
    } else { 
     // Touch in progress - !ended, !cancelled, just invalidate it 
     print("Invalidate auto lock timer") 
    } 

    super.sendEvent(event) 
    } 

} 

Pourquoi il y a @objc(MyApplication). C'est parce que Swift nomme les noms d'une autre manière que l'Objective-C et il dit simplement que le nom de ma classe en Objective-C est MyApplication.

Pour le faire fonctionner, ouvrez votre info.plist et ajoutez la ligne avec classe principale clé et MyApplication valeur (MyApplication est ce qui est à l'intérieur @objc(...), pas votre nom de classe Swift). La clé brute est NSPrincipalClass.

enter image description here

  0

Cela fonctionne !! Impressionnant!! Merci beaucoup!!!! 29 juil.. 152015-07-29 02:33:34

  0

Soyez conscient d'une chose - cela n'attrape pas les événements de clavier externes. Si vous avez un clavier BT ... Juste sur l'écran/logiciel. 29 juil.. 152015-07-29 04:52:32

  0

Merci pour les heads up. Cette application que je suis en train de construire va avoir des accessoires externes à taper alors je vais devoir examiner cela. 29 juil.. 152015-07-29 07:19:22

  0

n'oubliez pas d'importer UIKit en haut.C'est génial, exactement ce dont j'avais besoin. 22 juin. 162016-06-22 17:18:53

  0

Je ne peux pas obtenir ce travail .. est-ce que quelqu'un a cela? 18 déc.. 162016-12-18 06:37:48


0

UIWindow a aussi une méthode sendEvent que vous pouvez remplacer. Cela vous permettrait de suivre le temps écoulé depuis le dernier contact sur l'écran. Swift 4:

class IdlingWindow: UIWindow { 
    /// Tracks the last time this window was interacted with 
    var lastInteraction = Date.distantPast 

    override func sendEvent(_ event: UIEvent) { 
     super.sendEvent(event) 
     lastInteraction = Date() 
    } 
} 

Si vous utilisez un story-board, vous pouvez le charger dans didFinishLaunchingWithOptions:

@UIApplicationMain 
class AppDelegate: UIResponder, UIApplicationDelegate { 
    var window: IdlingWindow? 

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 
     window = IdlingWindow(frame: UIScreen.main.bounds) 
     window?.rootViewController = UIStoryboard.init(name: "Main", bundle: nil).instantiateInitialViewController() 
     window?.makeKeyAndVisible() 
     return true 
    } 
    : 
} 

extension UIApplication { 
    /// Conveniently gets the last interaction time 
    var lastInteraction: Date { 
     return (keyWindow as? IdlingWindow)?.lastInteraction ?? .distantPast 
    } 
} 

maintenant ailleurs dans votre application, vous pouvez vérifier l'inactivité comme ceci:

if UIApplication.shared.lastInteraction.timeIntervalSinceNow < -2 { 
    // the window has been idle over 2 seconds 
}