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.
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!
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
}