标签:c++ cocos2d-x editbox 输入框 控件
****************************************************************************
时间:2015-01-26
作者:Sharing_Li
转载出处:http://blog.csdn.net/sharing_li/article/details/42582625
****************************************************************************
在游戏开发当中,我们可能有比较特殊的需求,比如今天要讲解的,做一个具有游戏特色的简单的编辑输入框。还是老规矩,先看一下效果图吧,这里有三张,因为输入的键盘的弹出方式有三种,这里根据每种情况对其功能需求做一下简要说明:
首先是一般的形式:
(画面太美,不忍直视。。。)
功能需求:
1、只有点击输入框才弹出键盘;
2、键盘出来的简单动画和点击键盘按钮的简单动画;
3、输入框实时显示键盘的输入,可以删除输入内容;
4、点击确定按钮,或点击除了输入框和键盘的地方,键盘消失的简单动画。
有的时候,键盘弹出来会挡住输入框,看着有点不爽,所以我们可以如下方案:
功能需求:
1、和前一个相比,其实就是改变了键盘的弹出方式,其实也没改变,就是让原来不动的背景图也跟着一起动。
可是这种显示方案也不足,要是输入框所处的位置比较便上,那么背景图上移的时候,很可能就看不到输入框了。那么,问题来了,学挖掘机........键盘弹出方案哪家强?(打字打顺了~。~),想必大部分人都知道了,来看看最后一种显示:
功能需求:
1、和前面的相比,变成了全屏输入,多加了一个阴影层和输入框。
PS:1、补充下,那个键盘要适配屏幕的大小。
2、我们可以将键盘上的按钮图片换成具有自己游戏中的元素的图片
接下来,来看看代码的大致实现:
先浏览下头文件:
#ifndef _COLOR_EDIT_H_
#define _COLOR_EDIT_H_
#include "cocos2d.h"
#include "cocos-ext.h"
USING_NS_CC;
USING_NS_CC_EXT;
enum EditType
{
EditType_No = 0,
Edit_Number,
Edit_Alphabet,
Edit_PinYin
};
enum EditLocation
{
EditLocation_No = 0,
Location_Down,
Location_Nature,
Location_Screen
};
enum KeyBtn
{
Key_Num_0 = 0,
Key_Num_1,
Key_Num_2,
Key_Num_3,
Key_Num_4,
Key_Num_5,
Key_Num_6,
Key_Num_7,
Key_Num_8,
Key_Num_9,
Key_Delete,
Key_Sure
};
class ColorEdit : public cocos2d::Layer
{
public:
~ColorEdit();
ColorEdit();
static ColorEdit * create(const Size & size, const char * BgFile,Node * parent,EditLocation editLocation,EditType editType = Edit_Number);
static ColorEdit * create(const Size & size,Scale9Sprite * pBgSprite,Node * parent,EditLocation editLocation,EditType editType = Edit_Number);
bool myInit(Scale9Sprite * pBgSprite,Node * parent,EditLocation editLocation,EditType editType);
protected:
virtual bool onTouchBegan(Touch* touch, Event* pEvent);
void onNumBtnCallback(Ref * obj);
void onFunBtnCallback(Ref * obj);
int getMaxZOrder(Node * node);
void moveAction(bool isShow);
void updateText();
private:
Scale9Sprite * m_pEditBg;
Sprite * m_pKeyBoard;
EditType m_editType;
EditLocation m_editLocation;
Sprite * m_keyBg;
Node * m_pTarget;
bool m_isKeyShow;
std::string m_text;
};
#endif
再来具体看看实现部分:
首先初始化:
bool ColorEdit::myInit(Scale9Sprite * pBgSprite,Node * parent,EditLocation editLocation,EditType editType)
{
if (!Layer::init())
{
return false;
}
m_pEditBg = pBgSprite;
m_pTarget = parent;
m_editLocation = editLocation;
m_editType = editType;
this->addChild(m_pEditBg);
auto centerSize = m_pEditBg->getContentSize();
//这里要设置好九宫图中间的矩形的大小,因为我们要把输入的内容显示在上面,否则会看起来乱七八糟
m_pEditBg->setCapInsets(Rect(0,0,centerSize.width * 0.9,centerSize.height * 0.9));
auto pLabel = Label::createWithTTF("","fonts/Marker Felt.ttf",centerSize.height * 0.75);
pLabel->setColor(Color3B::WHITE);
pLabel->setAnchorPoint(Vec2(0,0.5));
pLabel->setTag(103);
pLabel->setPosition(Vec2(centerSize.width * 0.08,centerSize.height * 0.5));
m_pEditBg->addChild(pLabel,2);
//如果是全屏显示类型
if (m_editLocation == Location_Screen)
{
//添加阴影层,先隐藏
auto keyLayer = LayerColor::create(Color4B(0,0,0,100));
keyLayer->setPosition(Point::ZERO);
keyLayer->setTag(100);
m_pTarget->addChild(keyLayer,this->getMaxZOrder(parent) + 2);
keyLayer->setVisible(false);
//添加上方的输入框
auto key_bigbg = Scale9Sprite::create("coloredit/key_bigbg.png");
key_bigbg->setContentSize(Size(Director::getInstance()->getWinSize().width,key_bigbg->getContentSize().height));
key_bigbg->setTag(101);
key_bigbg->setAnchorPoint(Vec2(0.5,0));
auto upSize = key_bigbg->getContentSize();
key_bigbg->setPosition(Vec2(m_pTarget->getContentSize().width / 2,m_pTarget->getContentSize().height));
m_pTarget->addChild(key_bigbg,this->getMaxZOrder(parent) + 2);
//同样设置九宫图中间的矩形
key_bigbg->setCapInsets(Rect(0,0,upSize.width * 0.9,upSize.height * 0.9));
auto label_up = Label::createWithTTF("","fonts/Marker Felt.ttf",upSize.height * 0.75);
label_up->setColor(Color3B::WHITE);
label_up->setAnchorPoint(Vec2(0,0.5));
label_up->setTag(102);
label_up->setPosition(Vec2(upSize.width * 0.08,upSize.height / 2));
key_bigbg->addChild(label_up);
}
m_keyBg = Sprite::create("coloredit/key_bg.png");
m_keyBg->setAnchorPoint(Vec2(0.5,1));
m_keyBg->setPosition(Vec2(m_pTarget->getContentSize().width / 2,0));
m_pTarget->addChild(m_keyBg,this->getMaxZOrder(parent) + 2);
auto bgSize = m_keyBg->getContentSize();
auto pMenu = Menu::create();
pMenu->setPosition(Vec2::ZERO);
m_keyBg->addChild(pMenu);
if (m_editType == Edit_Number)//添加数字键盘
{
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 5; j++)
{
auto numSprNor = Sprite::create(__String::createWithFormat("coloredit/num_%d.png",i * 5 + j)->getCString());
auto numSprSel = Sprite::create(__String::createWithFormat("coloredit/num_%d.png",i * 5 + j)->getCString());
auto numBtn = MenuItemSprite::create(numSprNor,numSprSel,CC_CALLBACK_1(ColorEdit::onNumBtnCallback,this));
numBtn->setTag(Key_Num_0 + i * 5 + j);
numBtn->setPosition(Vec2(bgSize.width / 10 * (j * 2 + 1),bgSize.height / 6 * ((3 - i) * 2 - 1)));
pMenu->addChild(numBtn);
}
}
auto delSprNor = Sprite::create("coloredit/btn_del.png");
auto delSprSel = Sprite::create("coloredit/btn_del.png");
auto delBtn = MenuItemSprite::create(delSprNor,delSprSel,CC_CALLBACK_1(ColorEdit::onFunBtnCallback,this));
delBtn->setTag(Key_Delete);
delBtn->setPosition(Vec2(bgSize.width / 4 - 15,bgSize.height / 6));
pMenu->addChild(delBtn);
auto sureSprNor = Sprite::create("coloredit/btn_sure.png");
auto sureSprSel = Sprite::create("coloredit/btn_sure.png");
auto sureBtn = MenuItemSprite::create(sureSprNor,sureSprSel,CC_CALLBACK_1(ColorEdit::onFunBtnCallback,this));
sureBtn->setTag(Key_Sure);
sureBtn->setPosition(Vec2(bgSize.width / 4 * 3 + 15,bgSize.height / 6));
pMenu->addChild(sureBtn);
}
else if (m_editType == Edit_Alphabet)//和number差不多,多了些按钮而已
{
}
else if (m_editType == Edit_PinYin)//这个要是实现的话,就成输入法了,咱们还是调用系统的吧。
{
}
//简单暴力的屏幕适配
auto rate_x = Director::getInstance()->getWinSize().width / bgSize.width;
m_keyBg->setScaleX(rate_x);
auto listenerT = EventListenerTouchOneByOne::create();
listenerT->onTouchBegan = CC_CALLBACK_2(ColorEdit::onTouchBegan,this);
listenerT->setSwallowTouches(false);
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listenerT,this);
return true;
}
然后是触摸函数的实现:
bool ColorEdit::onTouchBegan(Touch* touch, Event* pEvent)
{
auto touchPoint = touch->getLocation();
//如果是全屏显示类型,并且键盘已弹出
if (m_editLocation == Location_Screen && m_isKeyShow)
{
auto key_upEdit = (Scale9Sprite *)m_pTarget->getChildByTag(101);
//如果点击除了顶层输入框和键盘的其他地方,则键盘消失
if (!m_keyBg->getBoundingBox().containsPoint(touchPoint) &&
!key_upEdit->getBoundingBox().containsPoint(touchPoint))
{
this->moveAction(false);
return true;
}
return false;
}
//将触摸点转为在当前子层下的坐标
touchPoint = this->convertToNodeSpace(touchPoint);
if (!m_pEditBg->getBoundingBox().containsPoint(touchPoint))
{
if (m_isKeyShow)
{
if (!m_keyBg->getBoundingBox().containsPoint(Vec2(touch->getLocation().x,
touch->getLocation().y - (m_editLocation == Location_Down ? 1 : 0) * m_keyBg->getContentSize().height)))
{
this->moveAction(false);
}
}
return false;
}
//如果点击了输入框,并且键盘还未弹出
if (!m_isKeyShow)
{
this->updateText();
this->moveAction(true);
}
return true;
}
这里有个要注意的地方:
if (!m_keyBg->getBoundingBox().containsPoint(Vec2(touch->getLocation().x,
touch->getLocation().y - (m_editLocation == Location_Down ? 1 : 0) * m_keyBg->getContentSize().height)))
{
this->moveAction(false);
}
当键盘的弹出方式是效果图第二张时,因为背景图向上移动了一段距离,touch->getLocation()的y坐标要做一下修改,否则getBoundingBox的判断不正确。
再来看看对于键盘点击的响应函数:
void ColorEdit::onNumBtnCallback(Ref * obj)
{
int tag = ((Node *)obj)->getTag();
//点击按钮的简单动画
((MenuItemSprite *)obj)->runAction(Sequence::create(ScaleTo::create(0.1,10 / 8.0),ScaleTo::create(0.1,1),NULL));
char temp[3];
sprintf(temp,"%d",tag);
m_text += temp;
//更新内容
this->updateText();
log("keyboard------->%d",tag);
}
void ColorEdit::onFunBtnCallback(Ref * obj)
{
((MenuItemSprite *)obj)->runAction(Sequence::create(ScaleTo::create(0.1,10 / 8.0),ScaleTo::create(0.1,1),NULL));
if (((Node *)obj)->getTag() == Key_Sure)
{
this->moveAction(false);
}
else
{
auto n = m_text.size();
if (n > 0)
{
m_text = m_text.substr(0,n - 1);
}
this->updateText();
}
}
接着是键盘的出现与消失:
void ColorEdit::moveAction(bool isShow)
{
if (m_editLocation == Location_Screen)
{
auto keyLayer = (LayerColor *)m_pTarget->getChildByTag(100);
auto key_upEdit = (Scale9Sprite *)m_pTarget->getChildByTag(101);
keyLayer->setVisible(isShow);
key_upEdit->runAction(MoveBy::create(0.35,Vec2(0,(isShow ? -1 : 1) * key_upEdit->getContentSize().height)));
m_keyBg->runAction(MoveBy::create(0.35,Vec2(0,(isShow ? 1 : -1) * m_keyBg->getContentSize().height)));
}
else if (m_editLocation == Location_Down)
{
Director::getInstance()->getRunningScene()->runAction(MoveBy::create(0.35,Vec2(0,(isShow ? 1 : -1) * m_keyBg->getContentSize().height)));
}
else if (m_editLocation == Location_Nature)
{
m_keyBg->runAction(MoveBy::create(0.35,Vec2(0,(isShow ? 1 : -1) * m_keyBg->getContentSize().height)));
}
m_isKeyShow = isShow;
if (!isShow)
{
m_text = "";
}
}
剩下的其他函数:
//获取最大的Zorder
int ColorEdit::getMaxZOrder(Node * node)
{
int zorder = -1;
Vector<Node *> nodeVec = node->getChildren();
for (auto node : nodeVec)
{
int temp = node->getLocalZOrder();
if (temp > zorder)
{
zorder = temp;
}
}
log("children's max zorder is %d",zorder);
return zorder;
}
void ColorEdit::updateText()
{
if (m_editLocation == Location_Screen)
{
((Label *)((Scale9Sprite *)(m_pTarget->getChildByTag(101)))->getChildByTag(102))->setString(m_text);
}
else
{
((Label *)(m_pEditBg->getChildByTag(103)))->setString(m_text);
}
}
最后我们在使用的时候,只需几行代码就行了。
auto colorEdit = ColorEdit::create(Size(250,40),"coloredit/input_box.png",this,Location_Nature);
colorEdit->setPosition(Vec2(bgSize.width / 2,bgSize.height / 2));
bg->addChild(colorEdit);
到这里基本上说完了,写的不好的地方还请见谅。
资源下载处:http://download.csdn.net/detail/sharing_li/8398363
标签:c++ cocos2d-x editbox 输入框 控件
原文地址:http://blog.csdn.net/sharing_li/article/details/42582625