|
实现:直接通过CCIMEDelegate实现字符的录入,删除,支持中英文混合输入,支持多个 EditBox 焦点切换,支持自动调整输入框位置等等一些列,应该满足一般游戏的需求。 主要平台:WIN32,IOS, android未测试。 优点:可以很容易的将 EditBox 控件在 cocos2dx 中融合。 缺点:当然没有原生的功能强。
#ifndef EDITBOX_H_INCLUDED #define EDITBOX_H_INCLUDED
namespace azl {
class EditBox; class EditBoxListener { public: virtual void onEditBoxChange(yy::EditBox* editBox) = 0; virtual void onEditBoxReturn(yy::EditBox* editBox) = 0; };
class EditBox : public cocos2d::CCNode, public cocos2d::CCIMEDelegate, public cocos2d::CCTouchDelegate { public: enum TYPE { TYPE_NORMAL = 1, TYPE_PASSWORD = 2, };
public: EditBox(); ~EditBox();
public: virtual bool attachWithIME(); virtual bool detachWithIME();
public: virtual bool canAttachWithIME() { return true; } virtual void didAttachWithIME(); virtual bool canDetachWithIME() { return true; } virtual void didDetachWithIME();
public: virtual void insertText(const char * text, int len); virtual void deleteBackward(); virtual const char * getContentText() { return getString().c_str(); }
public: virtual void keyboardWillShow(cocos2d::CCIMEKeyboardNotificationInfo& info); virtual void keyboardDidShow(cocos2d::CCIMEKeyboardNotificationInfo& info); virtual void keyboardWillHide(cocos2d::CCIMEKeyboardNotificationInfo& info); virtual void keyboardDidHide(cocos2d::CCIMEKeyboardNotificationInfo& info);
public: virtual bool ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent); virtual void ccTouchMoved(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent); virtual void ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent); virtual void ccTouchCancelled(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent);
public: virtual void setContentSize(const cocos2d::CCSize& contentSize) { cocos2d::CCNode::setContentSize(contentSize); updateString(); }
public: void updateCursor(float dt);
void onEnter(); void onExit(); void visit();
public: void setBackground(cocos2d::CCNode* background); cocos2d::CCNode* getBackground() { return background_; }
void setLabel(cocos2d::CCLabelTTF* label); cocos2d::CCLabelTTF* getLabel() { return contentLabel_; }
void setPlaceholderLabel(cocos2d::CCLabelTTF* label); cocos2d::CCLabelTTF* getPlaceholderLabel() { return placeholderLabel_; }
void setString(const std::string& text); const std::string& getString() { return contentText_; }
void setType(TYPE type); TYPE getType() { return type_; }
void setMaxChar(int maxChar); int getMaxChar() { return maxChar_; }
void setEnabled(bool enable) { enable_ = enable; } bool isEnabled() { return enable_; }
void setIsNumber(bool number) { isNumber_ = number; } bool isNumber() { return isNumber_; }
void setListener(EditBoxListener* listener) { listener_ = listener; } EditBoxListener* getListener() { return listener_; }
public: static EditBox* create(cocos2d::CCSize size, cocos2d::CCLabelTTF* label, cocos2d::CCLabelTTF* placeholderLabel = NULL, cocos2d::CCNode* background = NULL, TYPE type = TYPE_NORMAL);
private: void updateString();
private: cocos2d::CCNode* background_; cocos2d::CCLabelTTF* contentLabel_; cocos2d::CCLabelTTF* placeholderLabel_; std::string contentText_; TYPE type_; int cursorState_; int maxChar_; bool enable_; float adjustVert_; bool isNumber_;
EditBoxListener* listener_; std::vector<unsigned char> lengthStack_; };
}
#endif
// CPP #include "cocos2d.h" #include "EditBox.h" #include "AppDelegate.h"
using namespace cocos2d;
namespace {
static const char _charMap[] = { /**//* 00 */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /**//* 10 */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /**//* 20 */ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /**//* 30 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /**//* 40 */ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /**//* 50 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /**//* 60 */ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /**//* 70 */ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /**//* 80 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /**//* 90 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /**//* a0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /**//* b0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /**//* c0 */ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, /**//* d0 */ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, /**//* e0 */ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, /**//* f0 */ -4, -4, -4, -4, -4, -4, -4, -4, -5, -5, -5, -5, -6, -6, -1, -1, };
}
namespace azl {
static EditBox* g_currentEditBox_ = NULL;
EditBox::EditBox() : background_(NULL) , contentLabel_(NULL) , placeholderLabel_(NULL) , type_(TYPE_NORMAL) , cursorState_(-1) , maxChar_(64) , enable_(true) , adjustVert_(0) , isNumber_(false) , listener_(NULL) { }
EditBox::~EditBox() {
}
bool EditBox::attachWithIME() { bool bRet = CCIMEDelegate::attachWithIME(); if (bRet) { // open keyboard CCEGLView * pGlView = CCDirector::sharedDirector()->getOpenGLView(); if (pGlView) { #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) if (!isNumber()) { pGlView->setIMEKeyboardDefault(); } else { pGlView->setIMEKeyboardNumber(); } #endif pGlView->setIMEKeyboardState(true); } } return bRet; }
bool EditBox::detachWithIME() { bool bRet = CCIMEDelegate::detachWithIME(); if (bRet) { // close keyboard CCEGLView * pGlView = CCDirector::sharedDirector()->getOpenGLView(); if (pGlView) { pGlView->setIMEKeyboardState(false); } } return bRet; }
void EditBox::didAttachWithIME() { cursorState_ = 0; g_currentEditBox_ = this; }
void EditBox::didDetachWithIME() { cursorState_ = -1; #if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) g_currentEditBox_ = NULL; #endif }
void EditBox::insertText( const char * text, int len ) { if (!enable_ || !isVisible()) { return; }
bool enter = false; bool update = false;
for (int i = 0; i < len;) { int l = _charMap[(unsigned char)text[i]];
if ((int)contentText_.size() + (l < 0 ? -l : 1) > maxChar_) { for (; i < len; ++i) { if (text[i] == '\n') { enter = true; } }
break; }
if (l < 0) { if (!isNumber_) { update = true; lengthStack_.push_back(-l); for (int j = 0; j < -l; ++j) { contentText_.push_back(text[i + j]); } }
i += -l; } else { if (text[i] == '\n') { enter = true; break; }
if (isNumber_) { if (text[i] >= '0' && text[i] <= '9') { update = true; lengthStack_.push_back(1); contentText_.push_back(text[i]); } } else { update = true; lengthStack_.push_back(1); contentText_.push_back(text[i]); }
++i; } }
if (update) { updateString(); if (listener_) { listener_->onEditBoxChange(this); } }
if (enter) { detachWithIME(); if (listener_) { listener_->onEditBoxReturn(this); } } }
void EditBox::deleteBackward() { if (!contentText_.empty() && !lengthStack_.empty()) { contentText_ = contentText_.substr(0, contentText_.size() - lengthStack_.back()); lengthStack_.pop_back();
updateString(); if (listener_) { listener_->onEditBoxChange(this); } } }
void EditBox::keyboardWillShow( CCIMEKeyboardNotificationInfo& info ) { if (g_currentEditBox_ != this) { return; } CCNode* node = this, *root = this; while ((node = node->getParent())) { root = node; } CCPoint position = root->getPosition(); if (adjustVert_ != 0) { root->setPosition(CCPoint(position.x, position.y - adjustVert_)); } adjustVert_ = 0; CCPoint point = convertToWorldSpace(CCPointZero); float mY = info.end.getMaxY() + AppDelegate::getKeyboardOffsetY();
if (mY > point.y) { adjustVert_ = mY - point.y + 4 + CCDirector::sharedDirector()->getVisibleOrigin().y; position = root->getPosition(); root->setPosition(CCPoint(position.x, position.y + adjustVert_)); } }
void EditBox::keyboardDidShow( CCIMEKeyboardNotificationInfo& info ) {
}
void EditBox::keyboardWillHide( CCIMEKeyboardNotificationInfo& info ) { if (g_currentEditBox_ != this) { return; } if (adjustVert_ != 0) { CCNode* node = this, *root = this; while ((node = node->getParent())) { root = node; } CCPoint position = root->getPosition(); root->setPosition(CCPoint(position.x, position.y - adjustVert_)); adjustVert_ = 0; }
}
void EditBox::keyboardDidHide( CCIMEKeyboardNotificationInfo& info ) { #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) g_currentEditBox_ = NULL; #endif }
bool EditBox::ccTouchBegan( CCTouch *pTouch, CCEvent *pEvent ) { if (isVisible() && enable_) { CCRect rect; rect.origin = CCPointZero; rect.size = getContentSize(); CCPoint position = convertTouchToNodeSpace(pTouch); if (rect.containsPoint(position)) { attachWithIME(); return true; } else { detachWithIME(); } }
return false; }
void EditBox::ccTouchMoved( CCTouch *pTouch, CCEvent *pEvent ) { CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent); }
void EditBox::ccTouchEnded( CCTouch *pTouch, CCEvent *pEvent ) { CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent); }
void EditBox::ccTouchCancelled( CCTouch *pTouch, CCEvent *pEvent ) { CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent); }
void EditBox::updateCursor( float dt ) { if (cursorState_ != -1) { cursorState_ = (++cursorState_ % 2); } }
void EditBox::onEnter() { schedule(SEL_SCHEDULE(&EditBox::updateCursor), 0.5); CCNode::onEnter(); CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, kCCMenuHandlerPriority, true); }
void EditBox::onExit() { CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this); unschedule(SEL_SCHEDULE(&EditBox::updateCursor)); CCNode::onExit(); }
void EditBox::visit() { if (!isVisible()) { return; }
glEnable(GL_SCISSOR_TEST);
CCPoint position = convertToWorldSpace(CCPointZero); CCSize size = getContentSize();
CCEGLView::sharedOpenGLView()->setScissorInPoints(position.x, position.y, size.width, size.height);
CCNode::visit();
if (cursorState_ == 1 && g_currentEditBox_ == this) { CCSize size = getContentSize(); CCPoint position1;
if (contentLabel_ && contentLabel_->isVisible()) { CCRect rect = contentLabel_->boundingBox();
if (size.width <= rect.size.width - 4) { position1 = CCPoint(size.width - 4, 0); } else { position1 = CCPoint(rect.size.width, 0); } } else { position1 = CCPointZero; }
position1.x = (position1.x < 2 ? 2 : position1.x); position1.y = -adjustVert_;
cocos2d::ccDrawColor4B(0, 0, 255, 128); for (int i = 2; i < 6; ++i) { cocos2d::ccDrawLine(cocos2d::CCPoint(position.x + position1.x + i , position.y + position1.y), cocos2d::CCPoint(position.x + position1.x + i , position.y + position1.y + size.height)); } }
glDisable(GL_SCISSOR_TEST); }
void EditBox::setBackground( cocos2d::CCNode* background ) { if (background_) { removeChild(background_, true); } addChild(background);
background_ = background; }
void EditBox::setLabel( cocos2d::CCLabelTTF* label ) { contentLabel_ = label; contentLabel_->setAnchorPoint(CCPointZero);
updateString(); }
void EditBox::setPlaceholderLabel( cocos2d::CCLabelTTF* label ) { placeholderLabel_ = label; placeholderLabel_->setAnchorPoint(CCPointZero);
updateString(); }
void EditBox::setString( const std::string& text ) { lengthStack_.clear(); contentText_ = ""; insertText(text.c_str(), (int)text.size()); // contentText_ = text; // // if (contentLabel_) // { // contentLabel_->setString(text.c_str()); // } // // updateString(); }
void EditBox::setType( TYPE type ) { type_ = type;
updateString(); }
void EditBox::setMaxChar( int maxChar ) { maxChar_ = maxChar; }
void EditBox::updateString() { if (contentText_.empty()) { if (contentLabel_) { contentLabel_->setString(""); }
if (placeholderLabel_) { placeholderLabel_->setVisible(true); if (contentLabel_) { contentLabel_->setVisible(false); }
CCRect rect = placeholderLabel_->boundingBox(); CCSize size = getContentSize();
placeholderLabel_->setPosition(CCPoint(0, ( size.height - rect.size.height ) / 2.0f)); } } else { if (contentLabel_) { contentLabel_->setVisible(true); if (placeholderLabel_) { placeholderLabel_->setVisible(false); }
if (type_ == TYPE_NORMAL) { contentLabel_->setString(contentText_.c_str()); } else if (type_ == TYPE_PASSWORD) { contentLabel_->setString(std::string().append(lengthStack_.size(), '*').c_str()); }
CCRect rect = contentLabel_->boundingBox(); CCSize size = getContentSize();
float y = ( size.height - rect.size.height) / 2.0f;
if (size.width - 4 <= rect.size.width) { contentLabel_->setPosition(CCPoint(size.width - rect.size.width - 4 , y)); } else { contentLabel_->setPosition(CCPoint(0, y)); } } } }
EditBox* EditBox::create( cocos2d::CCSize size, cocos2d::CCLabelTTF* label, cocos2d::CCLabelTTF* placeholderLabel /**//*= NULL*/, cocos2d::CCNode* background /**//*= NULL*/, TYPE type /**//*= TYPE_NORMAL*/ ) { EditBox* box = new EditBox; box->autorelease();
if (background) { background->setAnchorPoint(CCPointZero); background->setPosition(0, 0); box->addChild(background, 0); box->background_ = background; }
if (label) { label->setAnchorPoint(CCPointZero); box->addChild(label, 1); box->contentLabel_ = label; }
if (placeholderLabel) { placeholderLabel->setAnchorPoint(CCPointZero); box->addChild(placeholderLabel, 1); box->placeholderLabel_ = placeholderLabel; }
// { // cocos2d::CCMenu* menu = cocos2d::CCMenu::create(); // cocos2d::CCMenuItemLabel* label = cocos2d::CCMenuItemLabel::create( // cocos2d::CCLabelTTF::create("X", "Arial", 20)); // menu->addChild(label); // menu->setPosition(cocos2d::CCPoint(size.width, size.height / 2)); // box->addChild(menu); // }
box->setContentSize(size); box->type_ = type; box->updateString();
return box; }
}
|