按钮的使用,详见“4.4按钮的基本使用及9宫格缩放”。
旋钮控件,由“底座图片”、“进度条图片”和“控制按钮图片”3部分组成。如下图:
在界面上的最终效果:
初始状态:
具体代码如下:
ControlPotentiometer * potentiometer = ControlPotentiometer::create("potentiometerTrack.png",
"potentiometerProgress.png", "potentiometerButton.png");
potentiometer->setPosition(Vec2(100, 200));
this->addChild(potentiometer);
注意,此类控件需要添加扩展库的支持:
#include "cocos-ext.h"
USING_NS_CC_EXT;
若编译时提示: fatal error C1083: 无法打开包括文件:“extensions/ExtensionMacros.h: No such file or directory”。
则还需要在项目属性上附加包含目录:
选中工程右键“属性”->"配置属性“->"c/c++"->"常规”->"附加包含目录"中添加“”$(EngineRoot)
添加响应事件:
ControlPotentiometer * potentiometer = ControlPotentiometer::create("potentiometerTrack.png",
"potentiometerProgress.png", "potentiometerButton.png");
potentiometer->setPosition(Vec2(100, 200));
potentiometer->addTargetWithActionForControlEvents(this, cccontrol_selector(HelloWorld::onValueChanged), Control::EventType::VALUE_CHANGED);
this->addChild(potentiometer);
auto showValue = Label::createWithTTF(G2U("数值:"), "fonts/abc.ttf", 24);
showValue->setTextColor(Color4B::WHITE);
showValue->setTag(1);
showValue->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2));
this->addChild(showValue, 1);
void HelloWorld::onValueChanged(Ref* pSender, Control::EventType event)
{
ControlPotentiometer * potentiometer = (ControlPotentiometer*)pSender;
String *valueStr = String::createWithFormat("数值:%f", potentiometer->getValue());
Label * label = (Label*)getChildByTag(1);
label->setString(G2U(valueStr->getCString()));
}
跟旋钮控件类似,滑条空间也是由3部分组成:“背景图片”、“进度条图片”和“控制按钮图片”。如果把“控制按钮”设为透明的,则变成了游戏中的“血槽”,类似于进度条的效果。
创建和响应事件的方式也非常的类似:
#include "cocos-ext.h"
USING_NS_CC_EXT;
ControlSlider * slider = ControlSlider::create("sliderBg.png",
"sliderValue.png", "button.png");
slider->setPosition(Vec2(100, 200));
slider->setMinimumValue(0);
slider->setMaximumValue(5000);
slider->setValue(3000);
slider->addTargetWithActionForControlEvents(this, cccontrol_selector(HelloWorld::onValueChanged), Control::EventType::VALUE_CHANGED);
this->addChild(slider);
auto showValue = Label::createWithTTF(G2U("数值:"), "fonts/abc.ttf", 24);
showValue->setTextColor(Color4B::WHITE);
showValue->setTag(1);
showValue->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2));
this->addChild(showValue, 1);
void HelloWorld::onValueChanged(Ref* pSender, Control::EventType event)
{
ControlSlider * potentiometer = (ControlSlider*)pSender;
String *valueStr = String::createWithFormat("数值:%f", potentiometer->getValue());
Label * label = (Label*)getChildByTag(1);
label->setString(G2U(valueStr->getCString()));
}
最终效果如下:
复选框控件,由“背景图片”和“勾选图片”组成,类似“□”和“√”。创建和使用也非常简单,如下列代码:
#include "ui/UICheckBox.h"
CheckBox * checkBox = CheckBox::create("check_box_bg.png", "check_box_cross.png");
checkBox->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2 - 150));
checkBox->addCCSEventListener(CC_CALLBACK_2(HelloWorld::onCheckBox, this));
this->addChild(checkBox);
auto showValue = Label::createWithTTF(G2U("状态"), "fonts/abc.ttf", 24);
showValue->setTextColor(Color4B::WHITE);
showValue->setTag(1);
showValue->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2));
this->addChild(showValue, 1);
void HelloWorld::onCheckBox(Ref* pSender, int checkEvent)
{
Label * label = (Label*)getChildByTag(1);
if (checkEvent == CheckBoxEventType::CHECKBOX_STATE_EVENT_SELECTED)
{
label->setString(G2U("选中!"));
}
else if (checkEvent == CheckBoxEventType::CHECKBOX_STATE_EVENT_UNSELECTED)
{
label->setString(G2U("未选中!"));
}
}
简单滑条控件Slider是相对于ControlSlider来说,其功能和组成都较为简单。其界面只是由“背景图片”和“控制按钮图片”两部分组成。数值范围为百分比,在0到100之间变化。
#include "ui/UISlider.h"
Slider *slider = Slider::create("sliderBg.png", "button.png");
slider->setPosition(Vec2(visibleSize.width / 2, 200));
slider->addCCSEventListener(CC_CALLBACK_2(HelloWorld::onValueChanged, this));
this->addChild(slider);
auto showValue = Label::createWithTTF(G2U("数值:"), "fonts/abc.ttf", 24);
showValue->setTextColor(Color4B::WHITE);
showValue->setTag(1);
showValue->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2));
this->addChild(showValue);
void HelloWorld::onValueChanged(Ref* pSender, int event)
{
Slider * slider = (Slider*)pSender;
String *valueStr = String::createWithFormat("数值:%d", slider->getPercent());
Label * label = (Label*)getChildByTag(1);
label->setString(G2U(valueStr->getCString()));
}
最终效果:
进度条控件仅仅只有背景图片,默认从左向右增长,值从0.0f到100.0f增长,为百分比。创建和使用也比较简单:
#include "ui/UILoadingBar.h"
LoadingBar *loadingBar = LoadingBar::create("sliderBg.png", 50);
//loadingBar->setDirection(LoadingBar::Direction::RIGHT);//默认从左向右增长,用RIGHT则从右向左增长
loadingBar->setPosition(Vec2(visibleSize.width / 2, 200));
loadingBar->setTag(100);
this->addChild(loadingBar);
auto showValue = Label::createWithTTF(G2U("数值:"), "fonts/abc.ttf", 24);
showValue->setTextColor(Color4B::WHITE);
showValue->setTag(1);
showValue->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2));
this->addChild(showValue);
this->schedule(CC_SCHEDULE_SELECTOR(HelloWorld::onSchedule), 0.1f);
void HelloWorld::onSchedule(float time)
{
LoadingBar * loadingBar = (LoadingBar*)getChildByTag(100);
float percent = loadingBar->getPercent();
if (percent <= 99.0f)
{
percent += 1;
loadingBar->setPercent(percent);
String *valueStr = String::createWithFormat("数值:%.2f", loadingBar->getPercent());
Label * label = (Label*)getChildByTag(1);
label->setString(G2U(valueStr->getCString()));
}
else
{
this->unschedule(CC_SCHEDULE_SELECTOR(HelloWorld::onSchedule));
}
}
最终效果:
字符图集,也就是将图形化的文字放到一个文件中,按照非常规则的方式排列,然后给出每个“图文”所占的宽、高像素数,然后拿一个“字符映射集合”(其实就是一个字符串)来对应每个图文。在绘制时,根据所需要显示的字符串,来从中找出相应的图文拼接成图片显示出来!
创建和使用非常的简单:
#include "ui/UITextAtlas.h"
TextAtlas * textAtlas = TextAtlas::create("0123456789", "atlas.png", 140, 140, "0");
textAtlas->setString("0");
//textAtlas->setStringValue("0");
textAtlas->setPosition(Vec2(visibleSize.width / 2, 200));
textAtlas->setTag(1);
this->addChild(textAtlas);
this->schedule(CC_SCHEDULE_SELECTOR(HelloWorld::onSchedule), 0.1f);
void HelloWorld::onSchedule(float time)
{
TextAtlas * textAtlas = (TextAtlas *)getChildByTag(1);
string strValue = textAtlas->getString();
int value = atoi(strValue.c_str());
if (value < 100)
value++;
else
value = 0;
stringstream ss;
ss << value;
string s1 = ss.str();
textAtlas->setString(s1.c_str());
}
上面的代码功能是每隔0.1秒,显示一个逐步+1操作的数字,范围从0到100,循环显示。
最终效果如下:
cocos2d-x中,提供了功能强大的Label控件,让我们简单的加载各种格式的字体,按照我们想要的效果来显示一段文字。同时,Label提供了按最大行宽自动换行、设置颜色、设置阴影、描边、发光三个特效。
①基本使用
我们在场景cpp文件的init()方法中最后部分添加以下代码:
bool HelloWorld::init()
{
//////////原有代码//////////
//////函数最后部分添加///////
Label * label = Label::createWithTTF("", "fonts/arial.ttf", 24);
label->setString("aaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccdddddddddddddddeeeeeeeeeeeeeeee");
label->setLineBreakWithoutSpace(true);//开启自动换行
label->setMaxLineWidth(visibleSize.width - 200);//设置自动换行时的最大行宽
label->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2 + 100));
label->setName("label");
addChild(label);
return true;
}
运行时效果如下:
注意,系统默认字体是无法自动换行的,即便我们设定了相关属性。
②阴影效果
我们在上小节“①基本使用”的代码基础上,添加阴影效果:
label->enableShadow(Color4B::GREEN, Size(10, -5));
第一个参数为阴影的颜色,第二个参数为阴影相对于原文字的偏移量。
③描边、轮廓
我们在上小节“①基本使用”的代码基础上,添加描边效果:
label->enableOutline(Color4B::RED, 3);
第一个参数为描边的颜色,第二个参数为描边的宽度。
运行时效果如下:
④发光
我们在上小节“①基本使用”的代码基础上,添加发光效果:
label->enableGlow(Color4B::RED);
第一个参数为发光的颜色。
在原有文字的周围有淡淡的发光颜色。注意,Glow发光从某种角度来讲就是一种特殊的OutLine描边。因此Glow发光和OutLine效果只能显示一种,不能同时起效。
⑤获取单个字母
Label还提供一个非常强大的功能,我们可以获取某一个字母,获取的同时会转换成Sprite精灵对象,然后再操作它:
Label * label = Label::createWithTTF("", "fonts/arial.ttf", 24);
label->setString("Hello Label!");
label->setHeight(200);
label->setLineBreakWithoutSpace(true);//开启自动换行
label->setMaxLineWidth(visibleSize.width - 200);//设置自动换行时的最大行宽
label->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2));
label->setName("label");
addChild(label);
Sprite * letterH = label->getLetter(0);
letterH->setColor(Color3B::BLUE);
Sprite * letterL = label->getLetter(6);
letterL->setColor(Color3B::RED);
letterL->runAction(RepeatForever::create(RotateBy::create(1, 360)));
上述代码中,我们把第0个(下标)字母H设置为蓝色,把第6个字母(下标)设置为红色,并且执行旋转动作(动作Action参见后续章节)。
简单的根据字体和内容显示一段文字,但暂未找到如何设置文字间距和行间距。
#include "ui/UIText.h"
Text * text = Text::create(G2U("以前人们在四月开始收获\
\n躺在高高的谷堆上面笑着\n我穿过金黄的麦田\n去给稻草人唱歌\n等着落山风吹过"), "fonts/abc.ttf", 24);
text->setTextHorizontalAlignment(TextHAlignment::CENTER);//水平居中
text->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2 + text->getContentSize().height / 2));
this->addChild(text);
TextField是一种字符串编辑控件,可以在其中输入文字,还可以跟当前操作系统下的输入法进行交互。但目前发现其不能换行。
#include "ui/UITextField.h"
TextField *textField = TextField::create(G2U("文字输入测试!"), "fonts/abc.ttf", 24);
textField->setPosition(Vec2(100, 100));
//textField->setPasswordEnabled(true);//作为密码只显示“*”
//textField->setPasswordStyleText("x");//修改密码样式(默认为“*”)
//textField->setMaxLengthEnabled(true);//开启限定最大长度
//textField->setMaxLength(10);//最大长度10个字符,后面无法继续输入
textField->addEventListener(CC_CALLBACK_2(HelloWorld::onTextFieldEvent, this));
this->addChild(textField);
void HelloWorld::onTextFieldEvent(Ref* pSender, TextField::EventType event)
{
switch (event)
{
case TextField::EventType::ATTACH_WITH_IME:
TextField * textField = dynamic_cast<TextField*>(pSender);
Size screenSize = Director::getInstance()->getWinSize();
textField->runAction(MoveTo::create(0.225f,
Point(screenSize.width/2.0f, screenSize.height/2.0f+textField->getContentSize().height/2.0f)));
break;
}
}
最终效果:
编辑框,由底部图片(实际上是一个九宫格精灵)和其上的字符串组成。作用是在点击时弹出窗口来输入文字。我们可以把它用作类似于手机聊天窗口中的气泡显示样式。
#include "ui/UIEditBox/UIEditBox.h"
cocos2d::ui::Scale9Sprite *s9p = cocos2d::ui::Scale9Sprite::create("chat_bubble.png");
s9p->setCapInsets(CCRect(32, 32, 90, 90));//10,10决定了左上角那一格的大小,263,40是中心那一格的宽和高
s9p->setPreferredSize(CCSize(300, 150));//设定“建议尺寸”,即是拉伸后的尺寸
s9p->setPosition(400, 500);
cocos2d::ui::EditBox * editBox = cocos2d::ui::EditBox::create(Size(300, 100), s9p);
editBox->setContentSize(Size(200, 100));
editBox->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2));
editBox->setFont("fonts/abc.ttf", 24);
editBox->setFontColor(Color4B::WHITE);
editBox->setInputMode(cocos2d::ui::EditBox::InputMode::DECIMAL);
//editBox->setInputFlag(cocos2d::ui::EditBox::InputFlag::PASSWORD);//显示为密码
editBox->setPlaceHolder(G2U("点击输入"));
editBox->setDelegate(this);//绑定委托对象,来处理响应事件
this->addChild(editBox,1);
在此需要注意,EditBox不是通过callback来回调方法的,而是通过委托来实现响应事件的。因此,需要委托类继承EditBoxDelegate抽象类:
class HelloWorld : public cocos2d::Layer, public cocos2d::ui::EditBoxDelegate
{
………………
virtual void editBoxReturn(cocos2d::ui::EditBox* editBox);
virtual void editBoxTextChanged(cocos2d::ui::EditBox* editBox, const std::string& text);
virtual void editBoxEditingDidBegin(cocos2d::ui::EditBox* editBox);
virtual void editBoxEditingDidEnd(cocos2d::ui::EditBox* editBox);
}
//在editBox中按下回车键会响应该函数
void HelloWorld::editBoxReturn(cocos2d::ui::EditBox* editBox)
{
CCLOG("return pressed!");
}
void HelloWorld::editBoxTextChanged(cocos2d::ui::EditBox* editBox, const std::string& text)
{
//使用一个临时的Label,用于测量字符串实际占的大小
Label * tempLabel = Label::createWithTTF(text, "fonts/abc.ttf", 24);
Size origin = editBox->getContentSize();
origin.width = tempLabel->getContentSize().width + 182;
editBox->setContentSize(origin);
}
void HelloWorld::editBoxEditingDidBegin(cocos2d::ui::EditBox* editBox)
{
CCLOG("edit box text begin editing!");
}
void HelloWorld::editBoxEditingDidEnd(cocos2d::ui::EditBox* editBox)
{
CCLOG("edit box text end editing!");
}
最后一定要注意,由于老版cocos2d-x中的EditBox是放在cocos2d::extension::EditBox中的,因此在使用EditBox类时,最好用完全的路径名,如:cocos2d::ui::EditBox。因为若我们包含了extension扩展库,则在编译时要么报错(二义性,不知道用哪个EditBox),要么不报错却使用了扩展库中的EditBox从而导致运行结果不正确!
最终效果如下:
注意,上图中的背景图片大小,并不会根据内容来调整大小。我们上述例子中,是重载了editBoxTextChanged方法,在其中根据字符串的内容来调整气泡大小来实现动态调整的。字符串增长后,效果如下: