cocos2dx之彩色編輯輸入框的設計

****************************************************************************

時間: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



 

 

發佈了116 篇原創文章 · 獲贊 102 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章