swift2 如何在Swift 2中检测所有触摸

edqdpe6u  于 2022-11-06  发布在  Swift
关注(0)|答案(3)|浏览(286)

我正在尝试为我使用Swift 2开发的应用程序创建一个超时函数,但在Swift 2中,您可以将此代码放在应用程序代理中,它可以工作,但它不会检测任何键盘按下、按钮按下、文本字段按下等操作:

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();
        }
    }
}

在swift 2之前,我能够拥有AppDelegate子类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)
            [[InactivityModel instance] actionPerformed];
    }
}

上面的代码适用于每一次触摸,但swift的等效代码只适用于UIWindow层次结构之上不存在视图的情况。
有人知道如何检测应用程序中的每一次触摸吗?

juzqafwq

juzqafwq1#

由于我的应用程序中有类似的问题,我只是尝试修复它:

  • 覆盖UIWindow中的sendEvent-不起作用
  • 在委托中覆盖sendEvent-不起作用

所以唯一的方法就是提供自定义的UIApplication子类。我目前的代码(在iOS 9上运行)是:

@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)
  }

}

为什么会有@objc(MyApplication),那是因为Swift用一种与Objective-C不同的方式来处理名字,它只是说--我在Objective-C中的类名是MyApplication
要使它工作,打开你的info.plist并添加一行 Principal class 键和MyApplication值(MyApplication@objc(...)里面的内容,而不是你的Swift类名)。

m2xkgtsf

m2xkgtsf2#

UIWindow也有一个可以覆盖的sendEvent方法,它可以让你追踪自上次触摸屏幕以来的时间。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()
    }
}

如果您使用的是故事板,则可以将其加载到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
    }
}

现在,您可以在应用的其他位置检查非活动状态,如下所示:

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

jtjikinw3#

@markiv的回答很有魅力,有两个问题:

  • 键窗口
    • “”keyWindow“在iOS 13.0中已弃用:不应用于支持多个场景的应用程序,因为它会在所有连接的场景中返回一个关键窗口”*

可以这样解决:
let kw = UIApplication.shared.windows.filter {$0.isKeyWindow}.first找到here
请参阅@matt答案

  • AppDelegate -我收到此消息:
    • 如果应用程序委托要使用主情节提要文件,则必须实现window属性 *

一个可以子类化UIWindow -找到了答案here。将其与IdlingWindow类组合。
留言不见了。

var customWindow: IdlingWindow?    
var window: UIWindow? {
    get {
        customWindow = customWindow ?? IdlingWindow(frame: UIScreen.mainScreen().bounds)
        return customWindow
    }
    set { }
}

相关问题