zoukankan      html  css  js  c++  java
  • CoronaSDK之交互系统和事件检测

    事件(Event)是Corona应用程序的基础。他们用来触发不同事件对应的响应,例如触摸屏幕、检测一个特定的系统事件、定时器的完成、两个物理体的碰撞,等等。通常我们使用display object的对象方法addEventListener来添加处理函数,以关联需要监听的事件。

    1 Runtime事件(似乎也可以叫做全局事件)

    Runtime事件被分配给全局的Runtime监听器。这些事件并不直接和任何具体的对象相关;当然他们广播给所有感兴趣的监听器。Runtime event包括下列这些:

    • enterFrame:发生在每秒帧数间隔之间的事件(corona渲染一般每秒30或60帧)
    • system:某种由系统状况引发的事件,例如设备挂起应用或退出应用
    • orientation:当改变设备的方向,横向到竖向或者反之,而发生的事件

    下面的代码展示了一个应用如何响应system事件:

    local function onSystemEvent( event )
    
        local eventType = event.type
    
        if ( eventType == "applicationStart" ) then
            --occurs when the application is launched and all code in "main.lua" is executed
        elseif ( eventType == "applicationExit" ) then
            --occurs when the user or OS task manager quits the application
        elseif ( eventType == "applicationSuspend" ) then
            --perform all necessary actions for when the device suspends the application, i.e. during a phone call
        elseif ( eventType == "applicationResume" ) then
            --perform all necessary actions for when the app resumes from a suspended state
        elseif ( eventType == "applicationOpen" ) then
            --occurs when the application is asked to open a URL resource (Android and iOS only)
        end
    end
    
    Runtime:addEventListener( "system", onSystemEvent )

    2 本地事件(local event)

    本地事件被发送给一个单独的Listener,而不是广播给全局的运行时环境。一般本地事件包括下列事件:

    hit:当用户触摸设备屏幕时发生的事件

    collision:物理对象碰撞时发生的事件

    timer:在运行timer完成时发生的事件

    audio:当一个音频播放完成时分发的事件

     

    3 function listener 和 table listener

    Listener可以是一个function,也可以是一个table。

    当你一个function Listener被调用,它会接受一个table参数,作为event。

    local myListener = function( event )
        print( "Listener called with event of type: "..event.name )
    end
    
    Runtime:addEventListener( "touch", myListener )
    Runtime:addEventListener( "enterFrame", myListener )

    有时一个function Listener并不方便,因为当Listener被调用时一些变量并不在作用域里。在这种情况里,table Listener应该被使用。table Listener必须有一个有对应事件名的实例方法:

    --assume myClass and myClass:new() already exist
    
    function myClass:enterFrame( event )
        print( "enterFrame called at time: "..event.time )
    end
    
    function myClass:touch( event )
        print( "touch occurred at: "..event.x..","..event.y )
    end
    
    local myObject = myClass:new() 
    
    Runtime:addEventListener( "touch", myObject )
    Runtime:addEventListener( "enterFrame", myObject )

    注意:

    这里是对象方法,用的是“:”,而不是“.”。所以实际上函数内部是可以访问self引用的。这里的self就是myObject的引用。

    4 理解hit事件

    当用户触摸屏幕时,一个hit事件会生成并分发给显示层次中的显示对象(display object)。只有那些在屏幕上位置和触摸点位置发生交集的对象会收到事件。hit事件会以一个特定的顺序穿过这些对象。默认情况下,第一个收到事件的对象是发生交集的对象中最上层的显示对象,往下一个发生交集的显示对象会第二个收到事件,如此类推。

    hit事件会一直传递下去,除非它被处理掉。这意味着如果你有多个层叠在一起的对象,并且一个hit事件监听器被应用到所有这些对象,hit事件将会穿过着所有的对象。然而,你可以停止传递给下一个低层对象,这就需要你告诉corona这个event已经被处理了。简单的方法就是在事件处理函数直接返回一个true--这将会停止传递周期,并且阻止任何底下对象响应这个hit事件。

    local function myTouchListener( event )
    
        if ( event.phase == "began" ) then
            --code executed when the button is touched
            print( "object touched = "..tostring(event.target) )  --'event.target' is the touched object
        end
        return true  --prevents touch propagation to underlying objects
    end
    
    local myButton = display.newRect( 100, 100, 200, 50 )
    myButton:addEventListener( "touch", myTouchListener )

    注意:如果hit事件遍历了整个显示层次中所有的显示对象,仍然没有被处理,它将会像全局事件一样广播给Runtime Listener。换言之,runtime listener还有机会对未命中任何对象的触摸事件做出反应。

    4.1 设置焦点

    你可以直接发送任何hit事件给一个指定的display object,来为这个对象设置焦点。比如一个典型的button,如果用户触摸这个按钮--还没有抬起手-又滑出了按钮,这个按钮一般不应该激发一个行为。同理,如果手指滑出按钮并接触到另一个交互对象,你可能不想激活那个对象,因为触摸是从按钮开始的,而不是交互对象。

    解决这个问题的简单方法就如下,进入按钮时设置焦点,结束和取消时再取消焦点。这样滑出到其他对象时,其他对象都收不到事件

    local function myTouchListener( event )
    
        if ( event.phase == "began" ) then
            display.getCurrentStage():setFocus( event.target )  --'event.target' is the touched object
    
        elseif ( event.phase == "ended" or event.phase == "cancelled" ) then
            display.getCurrentStage():setFocus( nil )  --setting focus to 'nil' removes the focus
    
        end
        return true
    end
    
    local myButton = display.newRect( 100, 100, 200, 50 )
    myButton:addEventListener( "touch", myTouchListener )

    4.2 hit event具体分为

    • Tap
    • Touch
    • Multitouch

    5 event 参数

    上面举出的每个例子,事件都会被分发给事件监听函数。一个event参数始终会被传递给监听函数。

    local function myTouchListener( event )
    
        print( "Touch X location"..event.x )
        print( "Touch Y location"..event.y )
    end
    
    local myButton = display.newRect( 100, 100, 200, 50 )
    myButton:addEventListener( "touch", myTouchListener )

    注意:传递给myTouchListener函数的event参数中包含手指接触屏幕位置的x和y坐标。event参数关联的属性和event类型是一一关联的。什么事件 对应哪些属性。

    6 注册EventListener

    我们一般用对象方法addEventListener()来注册事件。只要传入事件名称字符串,以及对应处理这个事件的处理函数即可。

    --standard touch listener on an object
    myButton:addEventListener( "touch", myTouchListener )
    
    --Runtime 'system' event listener
    Runtime:addEventListener( "system", onSystemEvent )

    重要提示:

    如上所示,两种类型的事件监听器都可以通过addEventListener对象方法来创建:监听器附着到显示对象,或者监听器附着到全局Rumtime。

    当你创建一个显示对象或添加一个本地的touch事件监听器 给它,你需要通过引用函数来指定一个代码块给事件。这些代码处于他们自己内存的代码段当中,并且当显示对象被删除后依然存在。不过当显示对象被删除后,就没办法检测到新的事件,因为本地事件监听器(注意:是监听器,不是代码)已经被有效的删除,并不需要你显式地删除监听器。

    另一方面,Runtime事件监听器需要在你用完之后手动删除。此外,他们将继续运行,因为全局Runtime事件是全局的。不仅仅会导致内存泄漏,而且如果函数继续存在于Runtime中,并引用了不再存在的对象,程序也会崩溃。

    7 删除Event Listener

    大多数监听器(Listener),除了“enterFrame”之类的Runtime监听器,在显示对象被删除(obj:removeSelf或display.remove(obj))时将会被自动删除。但是,你也可以不删除对象,而只手动删除事件监听器。

    删除(摘除)一个事件监听器,需要依靠内建的removeEventListener对象方法。

    这个函数调用方式和addEventListener差不多。比如,你想让一个按钮停止监听touch事件,就可以摘除其监听器,如下:

    myButton:removeEventListener( "touch", myTouchListener )

    删除关联的事件监听器,需要提供事件名和函数名,因为有可能一个对象连接了同一类对象的多个监听器。例如,你可以有两个或更多监听函数关联到myButton的touch事件。然而当调用removeEventListener()时,你需要指定你想要停止监听的事件的类型,以及之前关联到这个事件上的函数。

  • 相关阅读:
    【Elasticsearch 技术分享】—— ES 常用名词及结构
    【Elasticsearch 技术分享】—— Elasticsearch ?倒排索引?这都是什么?
    除了读写锁,JUC 下面还有个 StampedLock!还不过来了解一下么?
    小伙伴想写个 IDEA 插件么?这些 API 了解一下!
    部署Microsoft.ReportViewe
    关于TFS强制undo他人check out
    几段查看数据库表占用硬盘空间的tsql
    How to perform validation on sumbit only
    TFS 2012 Disable Multiple Check-out
    在Chrome Console中加载jQuery
  • 原文地址:https://www.cnblogs.com/leezj/p/4238641.html
Copyright © 2011-2022 走看看