因为你重写了ontouchevent,而click或者longclick都是根据touch的motion来判断的
所以longclick不生效
基本思路:
1,自行判断,例如action down开始计时,当action up到来时,如果持续超过一定时间(比如1秒),并且move的范围小于一定阈值,认定为一次long click
2,使用gesture detector类判断手势
这里只针对lua
具体分为以下几种
1>单点触摸
注册函数为
ccHandlerEVENT_TOUCH_BEGAN = 40
ccHandlerEVENT_TOUCH_MOVED = 41
ccHandlerEVENT_TOUCH_ENDED = 42
ccHandlerEVENT_TOUCH_CANCELLED = 43
注册的时候必须通过
ccEventListenerTouchOneByOne:create() 创建listener
onTouchBegin/onTouchMove/onTouchEnd为自己注册的回调函数
代码如下:
local listener = ccEventListenerTouchOneByOne:create();
listener:registerScriptHandler(onTouchBegin,ccHandlerEVENT_TOUCH_BEGAN);
listener:registerScriptHandler(onTouchMove,ccHandlerEVENT_TOUCH_MOVED);
listener:registerScriptHandler(onTouchEnd,ccHandlerEVENT_TOUCH_ENDED);
2>多点点触摸
ccHandlerEVENT_TOUCHES_BEGAN = 44
ccHandlerEVENT_TOUCHES_MOVED = 45
ccHandlerEVENT_TOUCHES_ENDED = 46
ccHandlerEVENT_TOUCHES_CANCELLED = 47
注册的时候必须通过
ccEventListenerTouchAllAtOnce:create() 创建listener
onTouchesBegin/onTouchesMove/onTouchesEnd为自己注册的回调函数
代码如下:
local listener = ccEventListenerTouchAllAtOnce:create();
listener:registerScriptHandler(onTouchesBegin,ccHandlerEVENT_TOUCHES_BEGAN);
listener:registerScriptHandler(onTouchesMove,ccHandlerEVENT_TOUCHES_MOVED);
listener:registerScriptHandler(onTouchesEnd,ccHandlerEVENT_TOUCHES_ENDED);
最后通过下面的代码绑定listener
ccDirector:getInstance():getEventDispatcher():addEventListenerWithSceneGraphPriority(listener,_layer);
其中_layer是要需要事件的对象
前面 ccDirector:getInstance() 也可用换成_layer 或者 _layer的父节点的对象
这里有几点需要注意:
1onTouchesBegin/onTouchBegin 里面需要 return true,表示需要处理这个事件,不然不会掉用onTouchMove/onTouchEnd
2每个触摸函数都包含2个参数 以onTouchMove为例:
local function onTouchMove(touch,event)
end
touch / event 都是userdata(可以理解为C/LUA共有的数据 只要实现了对应的方法 C/Lua可以直接访问/赋值/调用函数 由C管理这块内存)
touch 是当前的触摸点 以下是它的方法
/ Returns the current touch location in OpenGL coordinates
@return The current touch location in OpenGL coordinates
/
Vec2 getLocation() const;
/ Returns the previous touch location in OpenGL coordinates
@return The previous touch location in OpenGL coordinates
/
Vec2 getPreviousLocation() const;
/ Returns the start touch location in OpenGL coordinates
@return The start touch location in OpenGL coordinates
/
Vec2 getStartLocation() const;
/ Returns the delta of 2 current touches locations in screen coordinates
@return The delta of 2 current touches locations in screen coordinates
/
Vec2 getDelta() const;
/ Returns the current touch location in screen coordinates
@return The current touch location in screen coordinates
/
Vec2 getLocationInView() const;
/ Returns the previous touch location in screen coordinates
@return The previous touch location in screen coordinates
/
Vec2 getPreviousLocationInView() const;
/ Returns the start touch location in screen coordinates
@return The start touch location in screen coordinates
/
如下面的代码可以在onTouchMove中直接获取 用户手指的移动距离
local dis = touch:getDelta()
print(disx,disy);
如果是多点触摸 touch是一个table
touch[1] touch[2] touch[3]…是触摸的对应点
event 可以表明表明
1当前用户点击了那个object (event:getCurrentTarget())
2当前是press/move/release的那个状态 (event:getEventCode())
ccEventCode =
{
BEGAN = 0,
MOVED = 1,
ENDED = 2,
CANCELLED = 3,
}
所以我们可以通过一个回调函数来判断当前是那个 *** 作 而不用写3个函数
示例代码
local function onTouchBegin(touch,event)
local p = touch:getLocation();
p = _layer:convertToNodeSpace(p);
print(px,py)
return true;
end
local function onTouchMove(touch,event)
end
local function onTouchEnd(touch,event)
end
local function onTouchesBegin(touch,event)
return true;
end
local function onTouchesMove(touch,event)
for i = 1,tablegetn(touch) do
local location = touch[i]:getLocation()
print(i,locationx,locationy)
end
end
local function onTouchesEnd(touch,event)
print("onTouchesEnd");
end
_layer = ccLayer:create();
_layer:setTouchEnabled(true)
local listener1 = ccEventListenerTouchOneByOne:create();
listener1:registerScriptHandler(onTouchBegin,ccHandlerEVENT_TOUCH_BEGAN);
listener1:registerScriptHandler(onTouchMove,ccHandlerEVENT_TOUCH_MOVED);
listener1:registerScriptHandler(onTouchEnd,ccHandlerEVENT_TOUCH_ENDED);
--多点触摸
-- local listener2 = ccEventListenerTouchAllAtOnce:create()
--listener2:registerScriptHandler(onTouchesBegin,ccHandlerEVENT_TOUCHES_BEGAN )
-- listener2:registerScriptHandler(onTouchesMove,ccHandlerEVENT_TOUCHES_MOVED )
-- listener2:registerScriptHandler(onTouchesEnd,ccHandlerEVENT_TOUCHES_MOVED )
local eventDispatcher = _layer:getEventDispatcher()
eventDispatcher:addEventListenerWithSceneGraphPriority(listener1, _layer)
--eventDispatcher:addEventListenerWithSceneGraphPriority(listener2, _layer)
2直接看代码
local function onTouchEvent(state , )
local args = {};
print(state);
for k,v in pairs(args[1]) do
print(k,v)
end
end
_layer:registerScriptTouchHandler(onTouchEvent,true,0,false);
@onTouchEvent 回调
@ture表示捕获要捕获多点触摸
@0优先级
@false 是否吞没触摸事件
如果是单点触摸 args[1] ->x,y,id
如果是多点触摸 args[1] ->x1,y1,id1,x2,y2,id2
这里cocos2dx-lua封装了 Layer:onTouch(callback, isMultiTouches, swallowTouches)
建议直接使用
这里如果你用cocos2dx-lua 的 lua-empty-test 做模板建立工程 有个bug
需要在 didFinishLaunchingWithOptions 添加代码
[eaglView setMultipleTouchEnabled:YES];
来打开多点触摸 这里我浪费了半天事件调试 FUCK
Android的事件处理的三种方法:
setOnClickListener,setOnLongClickListener、setOnTouchListener
注意:如果onTouchEvent方法return true,则单击事件和长摁事件不再执行;若onLongClick方法返回true,则单击事件不再处理。
需要定义继承组件的类,重写回调方法Touch方法执行时,先被Activity捕获,DispatchTouchEvent方法处理。return false,交给上层的onTouchEvent方法处理;return superdispatchTouchEvent(ev),则传递给最外层的View。
View用Dispatch方法处理,return false,由上层的onTouchEvent方法处理。如果返回superdispatchTouchEvent(ev),则本层的onInterceptTouchEvent拦截,如果拦截true,则拦截,false不拦截,传递给子View的DispatchTouchEvent处理。
常用的回调方法:onKeyDown,onKeyLongPress,onKeyUp,onTouchEvent,onTrackballEvent(轨迹球事件)监听和回调同时存在时,先调用监听。
流程模型图:
Event source 事件源
Event 事件
Event Listener 事件监听器
下面我们来看一下点击事件和触摸事件的监听三要素具体是那部分:
由于点击事件比较简单,系统已经帮我们处理了,并没有找到具体事件是哪个。
ViewOnClickListener 单击事件监听器必须实现的接⼝
ViewOnCreateContextMenuListener 创建上下⽂菜单事件
ViewOnFocusChangeListener 焦点改变事件
ViewOnKeyListener 按键事件监听器
ViewOnLongClickListener 长按事件监听器
ViewOnTouchListener 触摸屏事件监听器
⾸先,事件监听机制中由事件源,事件,事件监听器三类对象组成。
事件监听器处理流程:
在此以OnClickListener单击事件为例使用intent来实现页面的跳转
监听事件处理是事件源与事件监听器分开的而基于回调的事件处理UI组件不但是事件源,而且还是事件监听器,通过组件的相关回调方法处理对应的事件。
Ⅰ 自定义View类,继承自需要的View UI类。ex :自定义 MyButton按钮类 extends 基础Button类
Ⅱ 复写回调函数。ex:public boolean onTouchEvent(MotionEvent event)
每一个事件回调方法都会返回一个boolean值,①如果返回true:表示该事件已被处理,不再继续向外扩散,②如果返回false:表示事件继续向外扩散
而说到基于回调就离不开监听机制 。
几乎所有基于回调的事件处理方法都有一个boolean类型的返回值,该返回值用于表示该处理方法是否能完全处理该事件。
如果处理事件的回调方法返回true,表明该处理方法已经完全处理改事件,该事件不会传播出去。
如果处理事件的回调方法返回false,表明该处理方法并未完全处理该事件,该事件会传播出去。
对于基于回调的时间传播而言,某组件上所发生的事件不仅会激发该组件上的回调方法,也会触发该组件所在Activity的回调方法——只要事件能传播到该Activity。
这里是在模拟器里进行的测试,这里按下键盘(而不是点击),会看到 logcat 中的输出,如下:
View类实现了KeyEventCallback接口中的一系列回调函数,因此,基于回调的事件处理机制通过自定义View来实现,自定义View时重写这些事件处理方法即可。
Handler是一个消息分发对象。
Handler是Android系统提供的一套用来更新UI的机制,也是一套消息处理机制,可以通过Handler发消息,也可以通过Handler处理消息。
在下面介绍Handler机制前,首先得了解以下几个概念:
在子线程执行完耗时 *** 作,当Handler发送消息时,将会调用 MessageQueueenqueueMessage ,向消息队列中添加消息。 当通过 Looperloop 开启循环后,会不断地从消息池中读取消息,即调用 MessageQueuenext , 然后调用目标Handler(即发送该消息的Handler)的 dispatchMessage 方法传递消息, 然后返回到Handler所在线程,目标Handler收到消息,调用 handleMessage 方法,接收消息,处理消息。
从上面可以看出,在子线程中创建Handler之前,要调用 Looperprepare() 方法,Handler创建后,还要调用 Looperloop() 方法。而前面我们在主线程创建Handler却不要这两个步骤,因为系统帮我们做了。
初始化Looper :
从上可以看出,不能重复创建Looper,每个线程只能创建一个。创建Looper,并保存在 ThreadLocal 。其中ThreadLocal是线程本地存储区(Thread Local Storage,简称TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的TLS区域。
开启Looper
发送消息 :
post方法:
send方法:
在子线程中,进行耗时 *** 作,执行完 *** 作后,发送消息,通知主线程更新UI。
本文讲解了三个方面;Android事件机制;基于监听、基于回调以及Handler消息处理。还有许多没有讲解到的知识点,我总结在了整理的一套Android进阶笔记里面;需要学习进阶的同学可以前往获取: Frame Work源码解析手册 、 Android核心技术进阶手册、实战笔记、面试题纲资料
这说明你的onTouchEvent没跑到,一般都是先跑onTouchEvent,更具返回值确定是手势滑动还是,点击按下 *** 作
public boolean onTouch(View v, MotionEvent event) {// surfaceWidth = vgetWidth();// surfaceHeight = vgetHeight(); int pointCount = eventgetPointerCount();
if (pointCount == 1) { float x = eventgetX(); float y = eventgetY(); switch (eventgetAction()) {
case MotionEventACTION_DOWN:// mMode = ModeDOUBLE_CLICK; eventLoop(x, y, CommonCONTROL_MSG_DOWN); initX = x; initY = y; break; case MotionEventACTION_UP: // eventLoop(x, y, CommonCONTROL_MSG_UP);// historyX = x;// historyY = y; initX = 0; initY = 0;// mMode = ModeUNDEFINED; break; } return mGestureDetectoronTouchEvent(event); } else { return false; } }
public void eventLoop(float x, float y, int action) { if (action == CommonCONTROL_MSG_MOVE) { mViewDraw(x, y, initX, initY); } else if (action == CommonCONTROL_MSG_DOWN) { mViewClick(x, y); } }}
这个我以前写的一个方法,一直在用,里面有返回值的情况,你照着把对应的 *** 作写下就行
onTouch是View中OnTouchListener接口中的方法,处理View及其子类被touch是的事件处理。当然,前提是touch时间能够传递到指定的view。
onTouchEvent同样也是在view中定义的一个方法。处理传递到view 的手势事件。手势事件类型包括ACTION_DOWN,ACTION_MOVE,ACTION_UP,ACTION_CANCEL四种事件。
一旦onTouchEvent方法被调用,并返回true则这个手势事件就结束了,并不会向下传递到子控件。
此方法返回false,则手势事件会向子控件传递;返回true,则调用onTouchEvent方法。
onTouchListener的接口的优先级是要高于onTouchEvent的,假若onTouchListener中的onTouch方法返回true,
表示此次事件已经被消费了,那onTouchEvent是接收不到消息的。
因为Button的performClick是利用onTouchEvent实现,假若onTouchEvent没有被调用到,那么Button的Click事件也无法响应。
onTouchListener的onTouch方法优先级比onTouchEvent高,会先触发。
假如onTouch方法返回false会接着触发onTouchEvent,反之onTouchEvent方法不会被调用。
内置诸如click事件的实现等等都基于onTouchEvent,假如onTouch返回true,这些事件将不会被触发。
buttonsetOnTouchListener(new ViewOnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
//按下 *** 作
if(motionEventgetAction()==MotionEventACTION_UP){
}
//抬起 *** 作
if(motionEventgetAction()==MotionEventACTION_UP){
}
//移动 *** 作
if(motionEventgetAction()==MotionEventACTION_MOVE){
}
return false;
}
});
以上就是关于JAVA自定义一个Button,重写了onTouchEvent 方法,出现的问题。全部的内容,包括:JAVA自定义一个Button,重写了onTouchEvent 方法,出现的问题。、用eventlistenertouchonebyone 创建的按钮在哪儿、Framework事件机制——手撕Android事件处理的三种方法等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)