Cocos2d经过几个版本的迭代,UI系统比较多,也比较乱,对于我们初学者来说,不必做到大而全,只需要掌握一种比较常用的就行。这篇文章主要介绍cocos studio中使用的UI系统。
Widget是整个UI系统的根类,它定义了UI控件共有的一些属性和方法,还有事件。
void UITest::WidgetTest(Widget *pWidget)
{
pWidget->setColor(Color3B(0, 128, 0));
pWidget->setBright(true);
pWidget->setEnabled(true);
pWidget->setFlippedX(true);
pWidget->setFlippedY(false);
pWidget->setBrightStyle(Widget::BrightStyle::HIGHLIGHT);
pWidget->setOpacity(255);
pWidget->setName("widget");
pWidget->setFocused(true);
pWidget->setVisible(true);
pWidget->setZOrder(100);
pWidget->setTag(1);
}
Zorder表示控件的显示深度,Zorder越大,控件越显示在顶层。3.0 之后 zorder 改名为 lcoalzorder,另外 还有一个 globalzorder,如果要调整层级关系的两个控件隶属于同一个父结点,则使用 localzorder 即可,否则要使用 globalzorder。
Widget 可以监听三个事件,触摸事件 TouchEventListener,点击事件 ClickEventListener 和 cocostudio事件 CCSEventListener
pWidget->addTouchEventListener(CC_CALLBACK_2(UITest::OnWidgetTouch, this));
pWidget->addClickEventListener(CC_CALLBACK_1(UITest::OnWidgetClick, this));
pWidget->addCCSEventListener(CC_CALLBACK_2(UITest::OnWidgetCCSEvent, this));
void UITest::OnWidgetTouch(Ref *pRef, Widget::TouchEventType type)
{
switch (type)
{
case Widget::TouchEventType::BEGAN:
log("touch begin");
break;
case Widget::TouchEventType::ENDED:
log("touch end");
break;
case Widget::TouchEventType::MOVED:
log("touch move");
case Widget::TouchEventType::CANCELED:
log("touch cancel");
break;
}
}
void UITest::OnWidgetClick(Ref *pRef)
{
log("click");
}
void UITest::OnWidgetCCSEvent(Ref *pRef, int id)
{
log("%d", id);
}
Widget *UITest::TestButton()
{
m_pButton = Button::create();
m_pButton->loadTextureNormal("res/Default/Button_Normal.png");
m_pButton->loadTextureDisabled("res/Default/Button_Disable.png");
m_pButton->loadTexturePressed("res/Default/Button_Press.png");
m_pButton->setTitleText("StartGame");
m_pButton->setTitleColor(Color3B(128, 0, 0));
WidgetTest(m_pButton);
return m_pButton;
}
按钮的主要事件是是触摸或者点击,这两个事件直接继承Widget,按钮没有特有的事件。
在旧版本中,使用文本可以Label,LabelTTF,LabelAtlas和LabelBMFont,新版本这几个类还保留,但它们不属于UI系统,新版本的引擎整合了几个新的类,它们属于UI系统的一部分,也是继承Widget,拥有Widget类的属性和事件方法。
Widget *UITest::TestText()
{
m_pText = Text::create("hello", "arial", 38);
WidgetTest(m_pText);
m_pText->setZOrder(20);
m_pText->setFontName("fonts/Marker Felt.ttf");
m_pText->setFontSize(36);
m_pText->setTextColor(Color4B(0, 255, 0, 255));
m_pText->setTextHorizontalAlignment(TextHAlignment::CENTER);
m_pText->setTextVerticalAlignment(TextVAlignment::CENTER);
return m_pText;
}
Widget *UITest::TestTextAtlas()
{
m_pTextAtlas = TextAtlas::create("1", "fonts/labelatlas.png", 32, 32, "0");
m_pTextAtlas->setString("123456");
WidgetTest(m_pTextAtlas);
return m_pTextAtlas;
}
Widget *UITest::TestTextBMF()
{
m_pTextBMF = TextBMFont::create("hello", "fonts/bitmapFontTest2.fnt");
WidgetTest(m_pTextBMF);
return m_pTextBMF;
}
文本也同样没有自己独有的事件。
使用 TextField 可以输入普通文本和密码。
Widget *UITest::TestTextField()
{
m_pTextField = TextField::create("please input", "arial", 30);
m_pTextField->setDetachWithIME(false);
m_pTextField->setAttachWithIME(false);
m_pTextField->setPasswordEnabled(true);
m_pTextField->setPasswordStyleText("*");
WidgetTest(m_pTextField);
return m_pTextField;
}
TexField有自己独有的事件
m_pTextField->addEventListener(CC_CALLBACK_2(UITest::OnTextFieldTrigger, this));
void UITest::OnTextFieldTrigger(Ref *pRef, TextField::EventType type)
{
switch (type)
{
case TextField::EventType::ATTACH_WITH_IME:
log("attach ime");
break;
case TextField::EventType::DETACH_WITH_IME:
log("detach ime");
break;
case TextField::EventType::INSERT_TEXT:
log("insert word");
break;
case TextField::EventType::DELETE_BACKWARD:
log("delete word");
break;
}
}
Widget *UITest::TestCheckBox()
{
m_pCheck = CheckBox::create();
m_pCheck->loadTextureBackGround("res/Default/CheckBox_Normal.png");
m_pCheck->loadTextureBackGroundDisabled("res/Default/CheckBox_Disable.png");
m_pCheck->loadTextureBackGroundSelected("res/Default/CheckBox_Press.png");
m_pCheck->loadTextureFrontCross("res/Default/CheckBoxNode_Normal.png");
m_pCheck->loadTextureFrontCrossDisabled("res/Default/CheckBoxNode_Disable.png");
m_pCheck->setSelected(true);
WidgetTest(m_pCheck);
m_pCheck->setEnabled(false);
return m_pCheck;
}
CheckBox 有选中和取消选中事件
m_pCheck->addEventListener(CC_CALLBACK_2(UITest::OnCheckBoxTrigger, this));
void UITest::OnCheckBoxTrigger(Ref *pRef, CheckBox::EventType type)
{
switch (type)
{
case CheckBox::EventType::SELECTED:
log("selected");
break;
case CheckBox::EventType::UNSELECTED:
log("unselected");
break;
}
}
Widget *UITest::TestSlider()
{
m_pSlider = Slider::create();
m_pSlider->loadBarTexture("sliderTrack.png");
m_pSlider->loadProgressBarTexture("sliderProgress.png");
m_pSlider->loadSlidBallTextureNormal("res/Default/SliderNode_Normal.png");
m_pSlider->loadSlidBallTexturePressed("res/Default/SliderNode_Press.png");
m_pSlider->loadSlidBallTextureDisabled("res/Default/SliderNode_Disable.png");
WidgetTest(m_pSlider);
return m_pSlider;
}
Slider事件
m_pSlider->addEventListener(CC_CALLBACK_2(UITest::OnSliderTrigger, this));
void UITest::OnSliderTrigger(Ref *pRef, Slider::EventType type)
{
switch (type)
{
case cocos2d::ui::Slider::EventType::ON_PERCENTAGE_CHANGED:
log("precent:%d%%", m_pSlider->getPercent());
break;
case cocos2d::ui::Slider::EventType::ON_SLIDEBALL_DOWN:
log("slider down");
break;
case cocos2d::ui::Slider::EventType::ON_SLIDEBALL_UP:
log("slider up");
break;
case cocos2d::ui::Slider::EventType::ON_SLIDEBALL_CANCEL:
log("slider cancel");
break;
default:
break;
}
}
Widget *UITest::TestLoadingBar()
{
m_pBar = LoadingBar::create();
m_pBar->loadTexture("res/Default/LoadingBarFile.png");
m_pBar->setPercent(50);
WidgetTest(m_pBar);
return m_pBar;
}
进度条没有自己独有的事件,但它通常需要一个计时器事件或其它事件来设置它的值。
除了 UI 事件外,cocos2d-x 中还有下面几种事件
在 c++ 中有两种方式添加事件,回调函数或者闭包
-- 回调函数
auto listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = CC_CALLBACK_2(UIFocusTest::onTouchedBeginTick, this);
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);
bool UIFocusTest::onTouchedBeginTick(Touch *t, Event *e)
{
log("touch");
return false;
}
-- 闭包
auto listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = [](Touch *t, Event *e) {
log("touch");
return false;
};
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);
在 lua 中也一样,只是 lua 中的闭包更加简单,不需要函数绑定
local function onTouchBegan(touch, event)
return true
end
local function onTouchMoved(touch, event)
end
local function onTouchEnded(touch, event)
end
self._listener = cc.EventListenerTouchOneByOne:create()
self._listener:registerScriptHandler(onTouchBegan, cc.Handler.EVENT_TOUCH_BEGAN)
self._listener:registerScriptHandler(onTouchMoved, cc.Handler.EVENT_TOUCH_MOVED)
self._listener:registerScriptHandler(onTouchEnded, cc.Handler.EVENT_TOUCH_ENDED)
cc.Director:getInstance():getEventDispatcher():addEventListenerWithSceneGraphPriority(self._listener, self._menu_btn)