cocos2d 2.0以後加入了一種九宮格的實現,主要做用是用來拉伸圖片,這樣的好處在於保留圖片四個角不變形的同時,對圖片中間部分進行拉伸,來知足一些控件的自適應(PS: 好比包括按鈕,對話框,最直觀的形象就是ios裏的短信氣泡了),這就要求圖片資源的中間部分是純色或者是簡單的漸變了!ios
1.cocos2d中九宮格CCScale9Sprite的實現
(1)原理
cocos2d的實現很是巧妙,是經過1個CCSpriteBatchNode和9個CCSprite來實現的,原理很簡單,經過將原紋理資源切割成9部分(PS: 這也是叫九宮格的緣由),根據想要的尺寸,完成如下的三個步驟:微信
a. 保持4個角部分不變形
b. 單向拉伸4條邊(即在4個角兩兩之間的邊,好比上邊,只作橫向拉伸)
c. 雙向拉伸中間部分(即九宮格的中間部分,橫向,縱向同時拉伸,PS:拉伸比例不必定相同)
(PS: 更多原理可參考 http://yannickloriot.com/2011/12/create-buttons-in-cocos2d-by-using-cccontrolbutton/)app
(2)實現
CCSpriteBatchNode的資源爲整個的紋理,9個CCSprite對應於紋理的9個部分(根據紋理不一樣,9部分所佔比例會有所不一樣),根據想要的尺寸,將9部分拼裝在一塊兒!函數
(3)優缺點
優勢:思路簡單清晰;使用CCSpriteBatchNode,只須要一次繪製,效率較高this
缺點:內存佔用大,須要1個CCSpriteBatchNode和9個CCSprite對象;不支持CCSpriteBatchNode(若是控件不少,咱們都須要對每一個控件單獨繪製一次,會影響效率)編碼
微信的對話框特色在於它有一個可變大小的底圖陪襯,顯得很是舒服,怎麼實現的呢?先上圖,而後慢慢說:
二、什麼是九宮格構圖?
有個概念叫九宮格構圖,說的就是這種會變化背景的狀況。你們都知道圖片是不能夠隨便拉抻的,不管是縮小仍是放大,都會使圖形虛化,影響顯示效果。不能拉抻就進行拼接。這就是這種策略的思路。
首先它現將一個圖分紅九份:
爲了可以看清楚,我進行了縮放。你們也看到了,縮放產生的問題。
拼接是如何進行的呢?當顯示應該超過圖片原有大小時,四個邊的頂點圖像不會改變,四個邊的中間部分進行拼接,這樣就擴展了圖片的大小。中間空出來的部分由中間來進行拼接。所以這張基礎圖不該該有花紋在上面,否則就會拼亂了。
三、編碼九宮格
原來縮放能夠這麼簡單的實現。並且使人高興的是cocos2d-x已經對這種模型進行封裝,不須要你們本身來寫。下面就動手編碼。
更改helloWorld中的init。相信你們都知道是哪裏:
- std::string str ="You are lucky as you can choose to love me or not.But for me,I can only choose to love you or more. ";
- // Create a label and initialize with string "Hello World".
- CCLabelTTF* pLabel =CCLabelTTF::create(str.c_str(),"Arial",24);
- CC_BREAK_IF(! pLabel);
- pLabel->setColor(ccc3(0,0,0));
pLabel->setAnchorPoint(CCPointZero);CCScale9Sprite* sp = CCScale9Sprite::create("green_edit.png");CCSize extenSize = CCSizeMake(pLabel->getContentSize().width+10,pLabel->getContentSize().height+10);sp->setContentSize(extenSize);sp->addChild(pLabel);pLabel->setPosition( ccpAdd(sp->getPosition(),ccp(4,1)));sp->setPosition(ccp(250,100)); // Add the label to HelloWorld layer as a child layer. this->addChild(sp, 1);spa
大致說一下。首先建立一個CCLabelTTF。而後取它的大小,做爲九宮格的大小。因爲不但願文字剛恰好貼在邊框顯示,我用一個extenSize將九宮格擴大了一圈。最後將Label添加爲九宮格的子節點。併爲其設定位置。
看起來不錯,不過編譯運行,出現的界面彷佛有些問題:
是的,沒有自動換行。
四、文字換行
文字換行怎麼辦?有個好消息是CCLabelTTF會爲字符串中有\n的地方換行。因此,我就人爲的在其中加入\n。能夠寫個函數作字符串轉換。若是有更好的解決方法歡迎留言告訴我。
編寫一個這樣的函數:
- std::stringHelloWorld::convertString( std::string str ,int length)
- {
-
- unsignedint before =0;
- vector<std::string> subStrs;
- do
- {
- subStrs.push_back(str.substr(before,length));
- if(before+length >str.size())
- {
- break;
- }
- else
- {
- before = before+length;
- }
- }while(true);
- std::string resultStr;
- for(unsignedint i =0;i<subStrs.size();++i)
- {
- resultStr.append(subStrs[i]).append("\n");
- }
- resultStr.pop_back();
- resultStr.pop_back();
- return resultStr;
- }
先將字符串按固定長度切成子串,加上\n,並拼起來,最後去掉多餘的\n。而後再更改建立Label那行:orm
- CCLabelTTF* pLabel =CCLabelTTF::create(convertString(str,32).c_str(),"Arial",24);
編譯運行,就能夠了。對象
五、總結
經過使用CCScale9Sprite這個類,建立一個可變大小的背景,而後建立固定寬度的Label,並將二者關聯。若是想進一步封裝的話,能夠建立一個類將二者做爲一個複合對象,具體可參照以前的文章: 。
CCScale9Sprite* nineGirl = CCScale9Sprite::create("button.png");
nineGirl->setContentSize(CCSize(200, 100)); //設置大小
nineGirl->setPosition(ccp(300, 200));
this->addChild(nineGirl);
/* 正常狀態下的按鈕圖片 */
CCScale9Sprite* btnNormal = CCScale9Sprite::create("button.png");
/* 點擊狀態下的按鈕圖片 */
CCScale9Sprite* btnDown = CCScale9Sprite::create("buttonHighlighted.png");
/* 按鈕標題 */
CCLabelTTF *title = CCLabelTTF::create("Touch Me!3324234", "Marker Felt", 30);
/* 按鈕的大小會根據標題自動調整 */
CCControlButton* controlBtn = CCControlButton::create(title, btnNormal);
/* 設置按鈕按下時的圖片 */
controlBtn->setBackgroundSpriteForState(btnDown, CCControlStateSelected);
controlBtn->setPosition(ccp(200, 200));
this->addChild(controlBtn);