监听各个GUI控件的交互事件
在GUI(图形用户界面)中,存在着许多不同类型的控件。为了更完美地使用这些控件,我们需要监听它们的交互事件。从Cocos2d-x 3.x版本开始,支持自有事件的控件都提供了addEventListener接口来设置各自的监听函数,并且使用functional来接收监听函数。
以TextField为例说明监听事件的设置步骤
1. 开启交互功能
在编辑器中设置交互,或者在程序中调用setTouchEnabled(true)。
2. 编写监听函数
void yourClass::textFieldEvent(Ref *pSender, TextField::EventType type) {
switch (type) {
case TextField::EventType::ATTACH_WITH_IME:
CCLOG("获得输入焦点");
break;
case TextField::EventType::DETACH_WITH_IME:
CCLOG("失去输入焦点");
break;
case TextField::EventType::INSERT_TEXT:
CCLOG("输入了文本");
break;
case TextField::EventType::DELETE_BACKWARD:
CCLOG("删除了文字");
break;
default:
break;
}
}
3. 设置监听
yourTextField->addEventListener(CC_CALLBACK_2(yourClass::textFieldEvent, this));
各个控件支持的自有事件(截止于3.3RC0)
输入框(ui::TextField)
enum class EventType {
ATTACH_WITH_IME, // 获得输入焦点
DETACH_WITH_IME, // 失去输入焦点
INSERT_TEXT, // 输入了文本
DELETE_BACKWARD // 删除了文字
};
复选框(ui::CheckBox)
enum class ui::CheckBox::EventType {
SELECTED, // 勾选了复选框
UNSELECTED // 取消勾选了复选框
};
滑动条(ui::Slider)
enum class ui::Slider::EventType {
ON_PERCENTAGE_CHANGED // 百分比改变
};
滚动层(ui::ScrollView)
enum class ui::ScrollView::EventType {
SCROLL_TO_TOP, // 滚动到顶时触发
SCROLL_TO_BOTTOM, // 滚动到底时触发
SCROLL_TO_LEFT, // 滚动到左边缘时触发
SCROLL_TO_RIGHT, // 滚动到右边缘时触发
SCROLLING, // 滚动时触发
BOUNCE_TOP, // 顶部回弹效果达到极限时触发
BOUNCE_BOTTOM, // 底部回弹效果达到极限时触发
BOUNCE_LEFT, // 左部回弹效果达到极限时触发
BOUNCE_RIGHT // 右部回弹效果达到极限时触发
};
列表容器(ui::ListView)
enum class ui::ListView::EventType {
ON_SELECTED_ITEM_START, // 点中某个项
ON_SELECTED_ITEM_END // 点中了某个项并抬起(没有发生滑动)
};
翻页容器(ui::PageView)
enum class EventType {
TURNING // 滚动到了页
};
通用触摸事件
其他所有Widget类型的节点都支持addTouchEventListener和addClickEventListener这两个接口,可通过这些接口来接收触摸事件。
addTouchEventListener的使用步骤(C++环境下)
- 准备好
widget节点,在编辑器中开启交互(或在代码中调用setTouchEnabled(true))。 - 定义一个函数,形式如下:
void ACuteClass::onTouchEvent(cocos2d::Ref *ref, Widget::TouchEventType touchType) { switch (touchType) { case Widget::TouchEventType::BEGAN: CCLOG("on began"); break; case Widget::TouchEventType::MOVED: CCLOG("on moved"); break; case Widget::TouchEventType::ENDED: CCLOG("on ended"); break; case Widget::TouchEventType::CANCELED: CCLOG("on canceled"); break; default: CCLOG("impossible"); break; } } - 将这个函数传递给
addTouchEventListener接口:your_widget->addTouchEventListener(CC_CALLBACK_2(ACuteClass::onTouchEvent, this)); // CC_CALLBACK_2照着写,表示有两个参数的回调。
addClickEventListener的使用方法与addTouchEventListener类似,不同之处在于:回调函数onTouchEvent在一次触摸中只回调一次,在触发ENDED时进行回调。
关于点击没响应的可能原因
- 未开启交互功能。
- 控件被其他元素挡住。
其他细节
1. 获取触摸事件的坐标
可以使用以下接口:
getTouchBeganPositiongetTouchMovePositiongetTouchEndPosition
2. ScrollView在某些情况下点到子控件不能拖动的问题
目前的Studio支持同时创建widget和非Widget类型的节点,这会引发一个问题。当Widget类型接收到触摸事件时,会将这些事件向上层传递,但在遇到非Widget节点时会停止传递。这会导致点击ScrollView等View类中的控件(两者之间有node)进行拖动时,拖动操作失败。
解决方案
- 设置
View中的控件的SwalloTouches属性为false,使控件不截断触摸事件。 - 或者修改源码,将如下代码替换掉
Widget中同名函数:void Widget::propagateTouchEvent(cocos2d::ui::Widget::TouchEventType event, cocos2d::ui::Widget *sender, cocos2d::Touch *touch) { Widget *widgetParent = nullptr; for (Node *p = this; widgetParent == nullptr;) { p = p->getParent(); if (p) { widgetParent = dynamic_cast<Widget*>(p); } else { return; } } widgetParent->interceptTouchEvent(event, sender, touch); }
(代码纯手打,若有问题烦请指出)