遊戲引擎一般提供兩種輸入框:editbox和textfielttf。editbox比較簡單,在ios上效果也還行,但是在android上就比較醜了,每次輸入都會懸浮一個小框框。對於遊戲來說eidtbox可以滿足基本需求,畢竟輸入還是少數情況。textfielttf是一種特殊的label,顯示效果比較好,但是計算起來比較麻煩,要自己繪製光標,要自己繪製文字,自己計算增加和刪除。
這裏還是說一下自己實現的一種簡陋的支持增加刪除的方式吧。其實比較簡單,原理就是記錄每個字及每個字的位置,然後增加刪除的時候既要對字處理也要對位置處理。(這裏只針對單行進行說明,多行的還要自己維護高度等信息)。
先來說一下繪製函數,這裏用的是自己維護的顯示內容contentString
bool CCTextFieldTTFExtend::onDraw(CCTextFieldTTF *pSender)
{
CCLog("the contentstring in fieldttf extend is %s", contentString.c_str());
//檢測是否有刪改
pSender->setString(contentString.c_str());
if (once == 1) {
once = 0;
if (recordPos.size() > 0 && pSender->getContentSize().width - recordPos[recordPos.size()-1].point.x < 0) {
//有記錄的數據,切操作之後顯示的文字內容比記錄的要短,說明進行的是刪除操作
if (posInList > 1) {
float distance = recordPos[posInList-2].point.x - recordPos[posInList-1].point.x;
m_pCursorSprite->setPositionX(m_pCursorSprite->getPositionX() + distance/2);
pSender->setString(contentString.c_str());
updateDelete(pSender);
}else if (posInList== 1){
float distance = 0 - recordPos[posInList-1].point.x;
m_pCursorSprite->setPositionX(m_pCursorSprite->getPositionX() + distance/2);
pSender->setString(contentString.c_str());
updateDelete(pSender);
}
return false;
}
if (recordPos.size() > 0 && pSender->getContentSize().width-recordPos[recordPos.size()-1].point.x > 1 ) {
//有記錄的數據,切操作之後顯示的文字內容比記錄的要長,說明進行的是增加操作
float distance = pSender->getContentSize().width - recordPos[recordPos.size()-1].point.x;
m_pCursorSprite->setPositionX(m_pCursorSprite->getPositionX() + distance/2);
pSender->setString(contentString.c_str());
updateAdd(pSender);
return false;
}else{
if(recordPos.size() == 0 && pSender->getContentSize().width > 0){
//顯現沒有記錄說明沒有文字,現在有記錄說明是增加操作
m_pCursorSprite->setPositionX(m_pCursorSprite->getPositionX() + pSender->getContentSize().width/2);
updateAdd(pSender);
}
}
}
return false;
}
刪除內容操作:
//刪除內容
void CCTextFieldTTFExtend::deleteString(){
if (strcmp(contentString.c_str(), "") && posInList < 1) {
return;
}
//計算刪除了幾個漢字或字符
int nDeleteLen = 1;
while(0x80 == (0xC0 & contentString.at(posInString - nDeleteLen)))
{
++nDeleteLen;
}
string tempNext = contentString.substr(posInString);
string tempPrev = contentString.substr(0, posInString-nDeleteLen);
contentString = tempPrev + tempNext;
posInString -= nDeleteLen;
once = 1;
}
增加內容操作:
//增加內容
void CCTextFieldTTFExtend::addString(const char *text){
string tempPrev = contentString.substr(0, posInString);
string tempNext = contentString.substr(posInString);
string tempString = tempPrev + text + tempNext;
int addLength = (strlen(tempString.c_str())-strlen(contentString.c_str()));
posInString += addLength;
contentString = tempString;
judgeChines = addLength;
CCLog("the contentString is %s", contentString.c_str());
once = 1;
}
刪除位置操作:
void CCTextFieldTTFExtend::updateDelete(CCTextFieldTTF * pSender){
//銷燬足跡
float distance = 0;
if (posInList != 0) {
distance = recordPos[posInList].point.x - recordPos[posInList-1].point.x;
}
vector<RecordTTF> temp = recordPos;
recordPos.clear();
for (int i = 0; i < posInList-1; ++ i) {
recordPos.push_back(temp[i]);
}
for (int i = posInList; i < temp.size(); ++ i) {
temp[i].point.x -= distance;
recordPos.push_back(temp[i]);
}
posInList --;
}
添加足跡的操作:
void CCTextFieldTTFExtend::updateAdd(CCTextFieldTTF * pSender){
//原先字段的前部
vector<RecordTTF> temp = recordPos;
recordPos.clear();
for (int i = 0; i < posInList; ++ i) {
recordPos.push_back(temp[i]);
}
//現增加的部分
float distance = 0;
if (posInList > 0) {
RecordTTF local;
distance = pSender->getContentSize().width - temp[temp.size()-1].point.x;
local.point = CCPoint(temp[posInList-1].point.x += distance, 0);
CCLog("現在的 %f", local.point.x);
local.flag = judgeChines;
recordPos.push_back(local);
}else{
if(temp.size() < 1){
RecordTTF local;
local.point = CCPoint(pSender->getContentSize().width, 0);
local.flag = judgeChines;
recordPos.push_back(local);
}else{
RecordTTF local;
CCLog("the contentSize is %f", pSender->getContentSize().width);
distance = pSender->getContentSize().width - temp[temp.size()-1].point.x;
local.point = CCPoint(temp[posInList-1].point.x += distance, 0);
CCLog("現在的 %f", local.point.x);
local.flag = judgeChines;
recordPos.push_back(local);
}
}
//原先文字的後部
for (int i = posInList; i < temp.size(); ++ i) {
temp[i].point.x += distance;
recordPos.push_back(temp[i]);
}
posInList ++;
}
-(void) handleTouchesAfterKeyboardShow
{
NSArray *subviews = self.subviews;
for(UIView* view in subviews)
{
if([view isKindOfClass:NSClassFromString(@"CustomUITextField")])
{
if ([view isFirstResponder])
{
[view resignFirstResponder];
return;
}
}
if([view isKindOfClass:NSClassFromString(@"UITextView")])
{
if ([view isFirstResponder])
{
[view resignFirstResponder];
return;
}
}
}
}
原因代碼也說的比較清楚了,原先quick只對自己的控件進行了處理,現在你增加一下把系統控件也處理以下。
此外,在做android微信授權登陸的時候出現從cocos2dActivity跳轉出去再跳轉回來之後所有的cocos2d輸入框不顯示鍵盤,跟蹤發現啓動鍵盤確實走到
Cocos2dxGLSurfaceView.sHandler = new Handler() {
@Override
public void handleMessage(final Message msg) {
switch (msg.what) {
case HANDLER_OPEN_IME_KEYBOARD:
Log.i("", "接收到啓動鍵盤通知");
if (null != Cocos2dxGLSurfaceView.this.mCocos2dxEditText && Cocos2dxGLSurfaceView.this.mCocos2dxEditText.requestFocus()) {
Log.i("", "接收到啓動鍵盤通知 開始啓動鍵盤");
Cocos2dxGLSurfaceView.this.mCocos2dxEditText.removeTextChangedListener(Cocos2dxGLSurfaceView.sCocos2dxTextInputWraper);
Cocos2dxGLSurfaceView.this.mCocos2dxEditText.setText("");
final String text = (String) msg.obj;
Cocos2dxGLSurfaceView.this.mCocos2dxEditText.append(text);
Cocos2dxGLSurfaceView.sCocos2dxTextInputWraper.setOriginText(text);
Cocos2dxGLSurfaceView.this.mCocos2dxEditText.addTextChangedListener(Cocos2dxGLSurfaceView.sCocos2dxTextInputWraper);
final InputMethodManager imm = (InputMethodManager) Cocos2dxGLSurfaceView.mCocos2dxGLSurfaceView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(Cocos2dxGLSurfaceView.this.mCocos2dxEditText, 0);
Log.d("GLSurfaceView", "showSoftInput");
}
break;
原因是我將微信授權的回調activity也設成了cocos2dActivity。具體是什麼造成的沒有去深究,將其改爲activity,並注意下到底是UIThread還是OpenGLThread,這樣的問題就沒有了。大部分這種操作都是線程混亂造成的,出現這種類似的情況,多看一下是否是線程的原因。