Detecting when an app is active or inactive throug

2019-03-11 18:50发布

问题:

This question already has an answer here:

  • How to detect all touches in Swift 2 2 answers

What code can be used to detect when a user is interacting with an app and when the user is not interacting with an app?

Currently I have a ViewController with a UIView that is receiving touches by overriding touches, also by receiving panning gestures and tap gestures. A solution to this problem needs to be separate to those current gestures or sit above those gestures.

Is there a gesture recognizer that sits above everything else that can tell my app when it received gestures and when there is no gesture received?

When the app is active, is there a way to monitor if the app is receiving touches and when it isn't and call a function as required, for example:

func appActive(){
    print("App received input from a touch, tap, swipe, long press etc.")
}

func appInactive(){
    print("App stopped receiving any input.")
}

Thank you.

回答1:

Swift 2. Xcode 7.2. Tested on iOS 7 - 9.

Adapted from: How to detect all touches in Swift 2 and Subclass UIApplication with Swift


1 - Locate your project's Swift file AppDelegate.swift, and comment out @UIApplicationMain:

//@UIApplicationMain

2 - Add a new Swift file to your project named exactly main.swift, and add the code:

import UIKit

UIApplicationMain(  
CommandLine.argc, UnsafeMutableRawPointer(CommandLine.unsafeArgv)  
    .bindMemory( to: UnsafeMutablePointer<Int8>.self,  
        capacity: Int(CommandLine.argc)), nil, NSStringFromClass(AppDelegate.self))  

3 - Add a new Swift file to your project named exactly UIApplication.swift, and add the code:

import UIKit

@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 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 timer
            print("Touches ended. Restart timer")
        } else {
            // Touches in progress - !ended, !cancelled, just invalidate it
            print("Touches in progress. Invalidate timer")
        }

        super.sendEvent(event)
    }
}

4 - Locate your project's Info.plist file, and add a new key (Xcode menu: Editor > Add Item), select or type key Principal class, with string value MyApplication.


5 - Run your project!




回答2:

A way to intercept any touches of your application is to create a custom UIWindow which will catch the touches without canceling them.

class CustomWindow: UIWindow {

    override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
        // Do any action you would like to perform to indicate the application is active
        return false
    }

}

You have to add this window in your Application Delegate, and set its level above the main window.

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var topWindow: CustomWindow?


    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
    {
        topWindow = CustomWindow(frame: UIScreen.mainScreen().bounds)
        topWindow?.rootViewController = UIViewController()
        topWindow?.windowLevel = UIWindowLevelNormal + 1
        topWindow?.hidden = false
        return true
    }