监听各个GUI控件的交互事件

2015年01月15日 14:54 0 点赞 0 评论 更新于 2025-11-21 14:29

在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类型的节点都支持addTouchEventListeneraddClickEventListener这两个接口,可通过这些接口来接收触摸事件。

addTouchEventListener的使用步骤(C++环境下)

  1. 准备好widget节点,在编辑器中开启交互(或在代码中调用setTouchEnabled(true))。
  2. 定义一个函数,形式如下:
    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;
    }
    }
    
  3. 将这个函数传递给addTouchEventListener接口:
    your_widget->addTouchEventListener(CC_CALLBACK_2(ACuteClass::onTouchEvent, this));
    // CC_CALLBACK_2照着写,表示有两个参数的回调。
    

addClickEventListener的使用方法与addTouchEventListener类似,不同之处在于:回调函数onTouchEvent在一次触摸中只回调一次,在触发ENDED时进行回调。

关于点击没响应的可能原因

  1. 未开启交互功能。
  2. 控件被其他元素挡住。

其他细节

1. 获取触摸事件的坐标

可以使用以下接口:

  • getTouchBeganPosition
  • getTouchMovePosition
  • getTouchEndPosition

2. ScrollView在某些情况下点到子控件不能拖动的问题

目前的Studio支持同时创建widget和非Widget类型的节点,这会引发一个问题。当Widget类型接收到触摸事件时,会将这些事件向上层传递,但在遇到非Widget节点时会停止传递。这会导致点击ScrollViewView类中的控件(两者之间有node)进行拖动时,拖动操作失败。

解决方案

  1. 设置View中的控件的SwalloTouches属性为false,使控件不截断触摸事件。
  2. 或者修改源码,将如下代码替换掉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);
    }
    

(代码纯手打,若有问题烦请指出)

作者信息

feifeila

feifeila

共发布了 3994 篇文章