cocos2d-x为我们提供了一个跨平台的输入框,CCTextFieldTTF,初看时感觉提供的功能很少,当看到tests中TextInputTest这个例子的时候,感觉它的使用还真是很复杂,其原因无非是一些设置和判断的繁琐。不过话说回来了,输入框最主要的是跨平台监听输入,而不是样式!至于我们想要做的,就是根据游戏的需要相对封装一个简单的输入框而已!
今天我就以一个简单的带光标的输入框为例子,简单的解释一下输入框的工作原理和简单的封装,做到了控件使用时的简单,但是这只是一个简单的模型,目前只支持单行输入!
这个类纯属是cocos2d-x的一个UI控件的扩展,当我们看到它的父类的时候,就会恍然大悟,喔!原来就是一个CCLabelTTF的子类啊!对,CCTextFieldTTF就是一个“动态”的CCLabelTTF,所谓的动态就是在监听到输入的时候动态的设置Label上的文字显示,仅此而已!而输入法的监听,则由其另一个父类CCIMEDelegate来实现。
class CC_DLL CCTextFieldTTF : public CCLabelTTF, public CCIMEDelegate
/** creates a CCTextFieldTTF from a fontname, alignment, dimension and font size */
static CCTextFieldTTF * textFieldWithPlaceHolder(const char *placeholder, const CCSize& dimensions, CCTextAlignment alignment, const char *fontName, float fontSize);
/** creates a CCLabelTTF from a fontname and font size */
static CCTextFieldTTF * textFieldWithPlaceHolder(const char *placeholder, const char *fontName, float fontSize);
/** initializes the CCTextFieldTTF with a font name, alignment, dimension and font size */
bool initWithPlaceHolder(const char *placeholder, const CCSize& dimensions, CCTextAlignment alignment, const char *fontName, float fontSize);
/** initializes the CCTextFieldTTF with a font name and font size */
bool initWithPlaceHolder(const char *placeholder, const char *fontName, float fontSize);
/**
@brief Open keyboard and receive input text.
*/
virtual bool attachWithIME();
/**
@brief End text input and close keyboard.
*/
virtual bool detachWithIME();
virtual void insertText(const char * text, int len);
virtual void deleteBackward();
virtual const char * getContentText();
偷个懒,输入的任务就交给cocos2d-x的CCTextFieldTTF了,输入框中字符串的处理我们需要CCTextFieldDelegate,而要从Layer中将触摸判断解放出来,我们还需要CCTouchDelegate,所以,我们的自定义输入框的声明会是这样
class CursorTextField: public CCTextFieldTTF, public CCTextFieldDelegate, public CCTouchDelegate
{
private:
// 点击开始位置
CCPoint m_beginPos;
// 光标精灵
CCSprite *m_pCursorSprite;
// 光标动画
CCAction *m_pCursorAction;
// 光标坐标
CCPoint m_cursorPos;
// 输入框内容
std::string *m_pInputText;
public:
CursorTextField();
~CursorTextField();
// static
static CursorTextField* textFieldWithPlaceHolder(const char *placeholder, const char *fontName, float fontSize);
// CCLayer
void onEnter();
void onExit();
// 初始化光标精灵
void initCursorSprite(int nHeight);
// CCTextFieldDelegate
virtual bool onTextFieldAttachWithIME(CCTextFieldTTF *pSender);
virtual bool onTextFieldDetachWithIME(CCTextFieldTTF * pSender);
virtual bool onTextFieldInsertText(CCTextFieldTTF * pSender, const char * text, int nLen);
virtual bool onTextFieldDeleteBackward(CCTextFieldTTF * pSender, const char * delText, int nLen);
// CCLayer Touch
bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);
void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);
// 判断是否点击在TextField处
bool isInTextField(CCTouch *pTouch);
// 得到TextField矩形
CCRect getRect();
// 打开输入法
void openIME();
// 关闭输入法
void closeIME();
};
#endif
(ps:这只是一个简单的版本,所以没有提供更复杂的初始化等方法,可以根据需要后续丰满)
a.延续了cocos2d-x的风格,将静态方法和初始化方法分开,这里几乎是CCTextFieldTTF的翻版,不过这里有一个小知识点,就是创建一个纯色精灵的办法,代码如下
int column = 4;
int pixels[nHeight][column];
for (int i=0; i<nHeight; ++i) {
for (int j=0; j<column; ++j) {
pixels[i][j] = 0xffffffff;
}
}
CCTexture2D *texture = new CCTexture2D();
texture->initWithData(pixels, kCCTexture2DPixelFormat_RGB888, 1, 1, CCSizeMake(column, nHeight));
m_pCursorSprite = CCSprite::spriteWithTexture(texture);
我用一个纯色精灵做了一个白色的光标,哈哈,虽然很山寨,但是在用的时候不用导入光标的图片资源了!
b.触摸判断
这个是有必要的,我们要判断触摸点是否在输入框上,如果在的话,需要弹出输入法;如果不在,需要关闭输入法,这样的用户体验还是不错的!
判断方法
bool CursorTextField::isInTextField(cocos2d::CCTouch *pTouch)
{
return CCRect::CCRectContainsPoint(getRect(), convertTouchToNodeSpaceAR(pTouch));
}
开启和关闭输入法的方法(顺便带上了光标的显示)
void CursorTextField::openIME()
{
m_pCursorSprite->setIsVisible(true);
this->attachWithIME();
}
void CursorTextField::closeIME()
{
m_pCursorSprite->setIsVisible(false);
this->detachWithIME();
}
c.还需要处理的地方是关于输入框中的字符串的添加和删减
我们可以监听到添加和删减,CCTextFieldDelegate所提供的方法,但是需要我们自己记录输入框中的内容,因为我们需要根据输入框中字符串的长度来确定光标的位置,而监听到添加字符的方法时,如果调用getString方法总会是差一个字符的,所以需要我们单独记录,我们手动调用setString方法,CCTextFieldTTF是根据字符串的宽度动态变化宽度的,于是有了下面的方法
bool CursorTextField::onTextFieldInsertText(cocos2d::CCTextFieldTTF *pSender, const char *text, int nLen)
{
CCLOG("Width: %f", pSender->getContentSize().width);
CCLOG("Text: %s", text);
CCLOG("Length: %d", nLen);
m_pInputText->append(text);
setString(m_pInputText->c_str());
m_pCursorSprite->setPositionX(getContentSize().width);
return true;
}
bool CursorTextField::onTextFieldDeleteBackward(cocos2d::CCTextFieldTTF *pSender, const char *delText, int nLen)
{
m_pInputText->resize(m_pInputText->size() - nLen);
setString(m_pInputText->c_str());
m_pCursorSprite->setPositionX(getContentSize().width);
if (m_pInputText->empty()) {
m_pCursorSprite->setPositionX(0);
}
return false;
}
我们想要的就是使用简单,我们想要的就是不去每层都设置触摸判断,我们想要的就是像cocos2d-x为我们提供的精灵一样使用,所以使用代码如下
m_pCursorTextField = CursorTextField::textFieldWithPlaceHolder("Input Text", "Thonburi", 64);
m_pCursorTextField->setPosition(ccp(winSize.width / 2, winSize.height / 2 + 100));
this->addChild(m_pCursorTextField);
这只是一个简单的例子,记录了一些简单的接口,目前只支持单行的正常显示,多行的和更完善的版本,下次补上!
源码下载