Colin-Liao 个人原创,欢迎转载,转载请注明地址。Colin-Liao的专栏地址http://blog.csdn.net/focusdeveloper
今天分享下如何做一个聊天窗口的文字输入框并且在其中提取汉字以及各种字符。
这个方法是相当于重写cocos2d-x中的CCTextFieldTTF这个类。那么下面看看头文件
#include
#include "cocos2d.h"
USING_NS_CC;
class ChatText: public CCTextFieldTTF, public CCTextFieldDelegate
{
CC_SYNTHESIZE(CCRect, textLabelRect, TextLabelRect);//输入框矩形
private:
// 光标精灵
CCSprite *m_pChatSprite;
// 光标动画
CCAction *m_pChatAction;
// 光标坐标
CCPoint m_chatPos;
// 输入框内容
std::string m_pInputText;
//输入框实际内容
std::string m_pInputString;
//输入框文字字节数组
int m_pInputCount[60];
//第几个文字
int index;
public:
ChatText();
~ChatText();
// static
static ChatText* textFieldWithPlaceHolder(const char *placeholder, const char *fontName, float fontSize);
// // CCLayer
void onEnter();
void onExit();
// 初始化光标精灵
void initChatSprite(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);
// 打开输入法
void openIME();
// 关闭输入法
void closeIME();
void emptyString();
//获得输入框实际内容
const char* getInputString();
};
这里继承了CCTextFieldTTF和CCTextFieldDelegate两个类,并且重写了其中的函数,之后会贴出每个函数的作用。
因为在屏幕上实现一个输入框的长度是有限的,但是当我们输入的文字超过这个输入框的时候,那么我们应该把前面的文字隐藏起来,这就是为什么这里会设置两个string ,m_pInputText是用来实际显示出来的文字内容,m_pInputString是输入框中实际文字内容。这里有一个整数数组,长度为60,也就是说可以输入60个字符,然后index为这个数组的下标。
下面贴出cpp文件中每个函数并且讲解
ChatText::ChatText()
{
CCTextFieldTTF();
m_pChatSprite = NULL;
m_pChatAction = NULL;
}
ChatText::~ChatText()
{
}
void ChatText::onEnter()
{
CCTextFieldTTF::onEnter();
this->setDelegate(this);
}
这里的onEnter函数中设置了输入框的Delegate。
ChatText * ChatText::textFieldWithPlaceHolder(const char *placeholder, const char *fontName, float fontSize)
{
ChatText *pRet = new ChatText();
if(pRet && pRet->initWithString("", fontName, fontSize))
{
pRet->autorelease();
if (placeholder)
{
pRet->setPlaceHolder(placeholder);
}
pRet->initChatSprite(fontSize);
return pRet;
}
CC_SAFE_DELETE(pRet);
return NULL;
}
这里是在创建这个输入框时候调用的函数,在函数中,new了一个ChatText,然后设置了他的PlaceHolder,这个参数是在输入框初始化时候灰色的文字,一般用作提示作用。
void ChatText::initChatSprite(int nHeight)
{
// 初始化光标
int column = 4;
int pixels[nHeight][column];
for (int i=0; iindex = -1;
CCTexture2D *texture = new CCTexture2D();
texture->initWithData(pixels, kCCTexture2DPixelFormat_RGB888, 1, 1, CCSizeMake(column, nHeight));
m_pChatSprite = CCSprite::createWithTexture(texture);
CCSize winSize = getContentSize();
m_chatPos = ccp(0, winSize.height / 2);
m_pChatSprite->setPosition(m_chatPos);
this->addChild(m_pChatSprite);
this->m_pChatAction = CCRepeatForever::create((CCActionInterval *) CCSequence::create(CCFadeOut::create(0.25f), CCFadeIn::create(0.25f), NULL));
this->m_pChatSprite->setVisible(false);
m_pChatSprite->runAction(m_pChatAction);
}
这个init主要作用是初始化光标,还有光标的动画。
bool ChatText::onTextFieldAttachWithIME(cocos2d::CCTextFieldTTF *pSender)
{
if (m_pInputText.empty()) {
return false;
}
m_pChatSprite->setPositionX(getContentSize().width);
return false;
}
这是来自CCTextFieldDelegate的回调函数,就是在打开输入法编辑器的时候会被调用,如果返回true则输入法编辑器不能被打开,这里返回的是yes并且设置了光标的位置为现在输入框中文字的宽度。
bool ChatText::onTextFieldInsertText(cocos2d::CCTextFieldTTF *pSender, const char *text, int nLen)
{
CCLOG("Width: %f", pSender->getContentSize().width);
CCLOG("Text: %s", text);
CCLOG("Length: %d", nLen);
if (*text == '\n') {
this->closeIME();
m_pChatSprite->setPositionX(0);
}else
{
//将输入文字一个一个解析上线为60
for (int i = 0; i < nLen; i++) {
char cha[6];
int count = 0;
unsigned char ch = *(text+i);
if (ch >=0x00 && ch <=0x7F) {
count = 1;
sprintf(cha, "%c",ch);
}else if(ch >=0xC0 && ch <=0xDF)
{
count =2;
sprintf(cha, "%c%c",ch,*(text+i+1));
i = i+1;
}
else if(ch >=0xE0 && ch <=0xEF)
{
count =3;
sprintf(cha, "%c%c%c",ch,*(text+i+1),*(text+i+2));
i = i+2;
}
else if(ch >=0xF0 && ch <=0xF7)
{
count =4;
sprintf(cha, "%c%c%c%c",ch,*(text+i+1),*(text+i+2),*(text+i+3));
i = i+3;
}
else if(ch >=0xF8 && ch <=0xFB)
{
count =5;
sprintf(cha, "%c%c%c%c%c",ch,*(text+i+1),*(text+i+2),*(text+i+3),*(text+i+4));
i = i+4;
}
else if(ch >=0xFC && ch <=0xFD)
{
count =6;
sprintf(cha, "%c%c%c%c%c%c",ch,*(text+i+1),*(text+i+2),*(text+i+3),*(text+i+4),*(text+i+5));
i = i+5;
}
if (this->index < 59) {
this->index = this->index+1;
m_pInputString.append(cha);
std::cout<index] = count;
}else
{
break;
}
}
if (this->index <= 59) {
int showAmount = 0;
int chinese = 0;
int chineseAmount = 0;
for (int i =this->index; i>= 0; i --) {
if (showAmount <=32) {
if (this->m_pInputCount[i] == 3) {
chinese = chinese + 1;
}
showAmount = showAmount + this->m_pInputCount[i];
}else
{
if (chinese == 0) {
break;
}
chineseAmount = chineseAmount + this->m_pInputCount[i];
if (chineseAmount > chinese) {
showAmount = showAmount + chineseAmount - this->m_pInputCount[i];
break;
}else if (i <=0)
{
showAmount = showAmount+ chineseAmount;
}
}
}
m_pInputText = m_pInputString.substr(m_pInputString.length() - showAmount);
setString(m_pInputText.c_str());
m_pChatSprite->setPositionX(getContentSize().width);
}
}
return true;
}
这个函数也是CCTextFieldDelegate的回调函数,在输入文字的时候被调用。当返回为true的时候输入的文字无效,不会被设置先是在输入框中,但是这里用自己将文字加入到了输入框。
当输入文字是首先判断是不是'\n'字符,如果是表示是收到了键盘上的return消息,这里处理为关闭键盘,并且设置了光标位置。如果不是return消息,就要对文字做解析了,之前有说到最多能够输入60个字符。
这里提到UTF8编码,它最多的字符有6个字节,每个字符的第一个字节在一定的范围内,通过上面的代码解析出来每个字符。如果index并没有超过59的话就通过string的append函数将解析出来的字符一个一个加入到输入框的实际内容中去,同时把每个字符的字节数量加入到整数数组中,以便之后分割字符串用,如果超过则结束循环。
然后对选择一些输入框的内容作为显示内容。同样先判断index是否已经超过59。在数组中读取出你能够显示在你屏幕上的字节数量,因为汉字占用三个字节导致p输入框不能显示尽量多的汉字,所以这里把汉字处理为两个字节。32这个数量可以自己设定,这是适合我自己的显示宽度。之后在实际内容的string中获取到子string加入到显示string上,并且设置为输入框的文字,再设置了光标位置。
bool ChatText::onTextFieldDeleteBackward(cocos2d::CCTextFieldTTF *pSender, const char *delText, int nLen)
{
this->m_pInputString = this->m_pInputString.substr(0,this->m_pInputString.length()-nLen);
this->index = this->index -1;
if (this->index <= 59) {
int showAmount = 0;
int chinese = 0;
int chineseAmount = 0;
for (int i =this->index; i>= 0; i --) {
if (showAmount <=32) {
if (this->m_pInputCount[i] == 3) {
chinese = chinese + 1;
}
showAmount = showAmount + this->m_pInputCount[i];
}else
{
if (chinese == 0) {
break;
}
chineseAmount = chineseAmount + this->m_pInputCount[i];
if (chineseAmount > chinese) {
showAmount = showAmount + chineseAmount - this->m_pInputCount[i];
break;
}else if (i <=0)
{
showAmount = showAmount+ chineseAmount;
}
}
}
m_pInputText = m_pInputString.substr(m_pInputString.length() - showAmount);
setString(m_pInputText.c_str());
m_pChatSprite->setPositionX(getContentSize().width);
if (m_pInputText.empty()) {
this->setPlaceHolder("输入聊天内容");
m_pChatSprite->setPositionX(0);
}
return true;
}
return false;
}
这个回调函数是删除字符,一个一个删除,如果返回true则不删除字符,这里原理为把实际内容最后一个字符删除,然后用上面的方法取出显示的字符串,设置为显示字符串,这样就向是删除后字符串向后面移动。别忘记设置index变量。
void ChatText::emptyString()
{
m_pInputText.resize(0);
this->m_pInputString.resize(0);
this->index = -1;
setString(m_pInputText.c_str());
if (m_pInputText.empty()) {
this->setPlaceHolder("输入聊天内容");
m_pChatSprite->setPositionX(0);
}
}
这个函数是 用来重置字符串的把idex设置为-1,把两个string设置为“”。string被重置。显示出提示信息。
bool ChatText::onTextFieldDetachWithIME(cocos2d::CCTextFieldTTF *pSender)
{
return false;
}
这个函数为键盘关闭的时候会调用,如果返回true,则键盘不被关闭。
void ChatText::openIME()
{
ChatUI* scene = (ChatUI*)this->getParent();
scene->setPosition(ccp(scene->getPosition().x, scene->getPosition().y+280));
m_pChatSprite->setVisible(true);
this->attachWithIME();
}
void ChatText::closeIME()
{
ChatUI* scene = (ChatUI*)this->getParent();
scene->setPosition(ccp(scene->getPosition().x, scene->getPosition().y-280));
m_pChatSprite->setVisible(false);
this->detachWithIME();
}
void ChatText::onExit()
{
CCTextFieldTTF::onExit();
}
const char* ChatText::getInputString()
{
return this->m_pInputString.c_str();
}
这几个函数第一个表示打开键盘,第二个 关闭键盘,分别调用父类的函数。最后一个表示获取输入框全部内容。
最后在别的界面中对触摸信息做一个处理点击到输入框的时候调出键盘。
更新一下在键盘调出之后,发现就无法在接收触摸消息了,解决方法在工程中找到EAGLView.mm文件在其touchesBegan,touchesBegan,touchesEnded,touchesCancelledtouchesMoved,
函数中注视掉其中判断键盘是否弹出就return的代码就好了
// if (isKeyboardShown_)
// {
// [self handleTouchesAfterKeyboardShow];
// return;
// }