Ios iPhone:检测自上次触摸屏幕以来的用户不活动/空闲时间
是否有人实现了一个功能,如果用户在某个时间段内没有触摸屏幕,您会采取某个操作?我在想最好的办法 UIC应用程序中有一种有点相关的方法:Ios iPhone:检测自上次触摸屏幕以来的用户不活动/空闲时间,ios,objective-c,iphone,idle-timer,Ios,Objective C,Iphone,Idle Timer,是否有人实现了一个功能,如果用户在某个时间段内没有触摸屏幕,您会采取某个操作?我在想最好的办法 UIC应用程序中有一种有点相关的方法: [UIApplication sharedApplication].idleTimerDisabled; 如果你有这样的东西就好了: NSTimeInterval timeElapsed = [UIApplication sharedApplication].idleTimeElapsed; 然后我可以设置一个计时器,定期检查这个值,当它超过阈值时采取一些措
[UIApplication sharedApplication].idleTimerDisabled;
如果你有这样的东西就好了:
NSTimeInterval timeElapsed = [UIApplication sharedApplication].idleTimeElapsed;
然后我可以设置一个计时器,定期检查这个值,当它超过阈值时采取一些措施
希望这能解释我在找什么。有没有人已经解决了这个问题,或者有没有想过你会怎么做?谢谢。 < P>你最终需要定义你认为闲置的是闲置的,如果没有计算资源,用户不接触屏幕的结果还是系统的状态?在许多应用中,即使用户没有通过触摸屏主动与设备交互,用户也有可能正在做一些事情。虽然用户可能熟悉设备进入睡眠状态的概念,并注意到它将通过屏幕变暗发生,但如果他们空闲,他们不一定会期望发生一些事情-您需要小心您将要做的事情。但是回到最初的陈述——如果你认为这第一个案例是你的定义,那么就没有一个简单的方法来做到这一点。您需要接收每个触摸事件,根据需要在响应器链上传递它,同时记录接收时间。这将为您进行空闲计算提供一些基础。如果你认为第二种情况是你的定义,那么你可以玩NSPStWORD空闲通知来尝试执行你当时的逻辑。 < P>这是我一直在寻找的答案: 让您的应用程序委托子类UIApplication。在实现文件中,重写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");
}
其中maxIdleTime和idleTimer是实例变量
为了使其正常工作,您还需要修改main.m,以告知UIApplicationMain使用您的委托类(在本例中为AppDelegate)作为主体类:
int retVal = UIApplicationMain(argc, argv, @"AppDelegate", @"AppDelegate");
这个线程是一个很大的帮助,我将它包装成一个UIWindow子类,用于发送通知。我选择通知使其成为真正的松耦合,但您可以很容易地添加委托 要点如下:
此外,UIApplication子类问题的原因是NIB被设置为创建2个UIApplication对象,因为它包含应用程序和委托。UIWindow子类工作得很好。实际上,子类化思想工作得很好。只是不要让您的委托成为
UIApplication
子类。创建另一个从UIApplication
继承的文件(例如myApp)。在IB中,将fileOwner
对象的类设置为myApp
,在myApp.m中实现上述sendEvent
方法。总的来说,我要:
int retVal = UIApplicationMain(argc,argv,@"myApp.m",@"myApp.m")
瞧 我有一个空闲计时器解决方案的变体,它不需要对UIApplication进行子类化。它适用于特定的UIViewController子类,因此,如果您只有一个视图控制器(如交互式应用程序或游戏),或者只想处理特定视图控制器中的空闲超时,那么它非常有用 它也不会在每次重置空闲计时器时重新创建NSTimer对象。只有当计时器启动时,它才会创建一个新的 您的代码可以调用
resetIdleTimer
,以处理可能需要使空闲计时器无效的任何其他事件(例如重要的加速计输入)
@interface MainViewController:UIViewController
{
n定时器*空闲定时器;
}
@结束
#定义kMaxIdleTimeSeconds 60.0
@实现主视图控制器
#布拉格标记-
#pragma标记处理空闲超时
-(无效)重置IDletimer{
if(!idleTimer){
idleTimer=[[NSTimer scheduledTimerWithTimeInterval:kMaxIdleTimeSeconds
目标:自我
选择器:@selector(已超出idletimer)
用户信息:无
重复:否]保留];
}
否则{
if(晶圆厂([idleTimer.fireDate timeIntervalSinceNow])
(为了简洁起见,不包括内存清理代码。)我刚刚遇到了一个由运动控制的游戏的问题,即禁用了屏幕锁定,但在菜单模式下应该再次启用。我没有使用计时器,而是将所有对
setIdleTimerDisabled
的调用封装在一个小类中,提供以下方法:
- (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];
}
禁用空闲定时器
禁用空闲定时器,enableIdleTimerDelayed
当进入菜单或任何应在空闲计时器处于活动状态下运行的内容时,将从AppDelegate的applicationWillResignActive
方法调用enableIdleTimer
,以确保将所有更改正确重置为系统默认行为。我写了一篇文章并提供了单例类IdleTimerManager的代码这里是另一种检测活动的方法: 计时器是在
UITrackingRunLoopMode
中添加的,因此它只能在UITracking
活动时触发。它还有一个很好的优点,就是不会对所有触摸事件向您发送垃圾邮件,从而通知您在最近的activity\u DETECT\u TIMER\u RESOLUTION
秒内是否有活动。我将选择器命名为keepAlive
,因为它似乎是合适的
- (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];
}
_touchesTimer = [NSTimer timerWithTimeInterval:ACTIVITY_DETECT_TIMER_RESOLUTION
target:self
selector:@selector(keepAlive)
userInfo:nil
repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:_touchesTimer forMode:UITrackingRunLoopMode];
extension NSNotification.Name {
public static let TimeOutUserInteraction: NSNotification.Name = NSNotification.Name(rawValue: "TimeOutUserInteraction")
}
class InterractionUIApplication: UIApplication {
static let ApplicationDidTimoutNotification = "AppTimout"
// The timeout in seconds for when to fire the idle timer.
let timeoutInSeconds: TimeInterval = 15 * 60
var idleTimer: Timer?
// Listen for any touch. If the screen receives a touch, the timer is reset.
override func sendEvent(_ event: UIEvent) {
super.sendEvent(event)
if idleTimer != nil {
self.resetIdleTimer()
}
if let touches = event.allTouches {
for touch in touches {
if touch.phase == UITouchPhase.began {
self.resetIdleTimer()
}
}
}
}
// Resent the timer because there was user interaction.
func resetIdleTimer() {
if let idleTimer = idleTimer {
idleTimer.invalidate()
}
idleTimer = Timer.scheduledTimer(timeInterval: timeoutInSeconds, target: self, selector: #selector(self.idleTimerExceeded), userInfo: nil, repeats: false)
}
// If the timer reaches the limit as defined in timeoutInSeconds, post this notification.
func idleTimerExceeded() {
NotificationCenter.default.post(name:Notification.Name.TimeOutUserInteraction, object: nil)
}
}
CommandLine.unsafeArgv.withMemoryRebound(to: UnsafeMutablePointer<Int8>.self, capacity: Int(CommandLine.argc)) {argv in
_ = UIApplicationMain(CommandLine.argc, argv, NSStringFromClass(InterractionUIApplication.self), NSStringFromClass(AppDelegate.self))
}
NotificationCenter.default.addObserver(self, selector: #selector(someFuncitonName), name: Notification.Name.TimeOutUserInteraction, object: nil)
fileprivate var timer ... //timer logic here
@objc public class CatchAllGesture : UIGestureRecognizer {
override public func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesBegan(touches, with: event)
}
override public func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
//reset your timer here
state = .failed
super.touchesEnded(touches, with: event)
}
override public func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesMoved(touches, with: event)
}
}
@objc extension YOURAPPAppDelegate {
func addGesture () {
let aGesture = CatchAllGesture(target: nil, action: nil)
aGesture.cancelsTouchesInView = false
self.window.addGestureRecognizer(aGesture)
}
}
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
import UIKit
class MyWindow: UIWindow {
override func sendEvent(_ event: UIEvent){
super.sendEvent(event)
NSLog("Application received an event. Do whatever you want")
}
}
self.window = MyWindow(frame: UIScreen.main.bounds)