Cocos2D-X ButtonLabel

Preface


在Cocos2D-X的GUI世界里蜕衡,Label(標簽)是最常用的UI控件之一驯绎,UIButton(按鈕)亦然督惰。但是仔細看辟拷,其實UIButton是Button和Label的組合體摧找。今天李皇,我們就來討論一下二者之間微妙的合作關(guān)系吓著。

ButtonLabel


3.0之前习贫,如果我沒記錯的話乳愉,默認的兄淫,UIButton都會有一個Label(這里就簡稱為ButtonLabel)屯远,其內(nèi)容稱之為TitleText(按鈕標簽)。我們可以通過getTitleRenderer獲得這個ButtonLabel:

Label* Button::getTitleRenderer()const
{
    return _titleRenderer;
}

所有對TitleText的操作都基于這個ButtonLabel捕虽,比如:

  • void Button::setTitleText(const std::string& text)
  • void Button::setTitleColor(const Color3B& color)
  • void Button::setTitleFontName(const std::string& fontName)
  • etc ...

值得一提的是慨丐,到了3.x之后,官方做了點優(yōu)化泄私,把ButtonLabel單獨拆出來房揭,這樣初始化的時候就不會創(chuàng)建多余的Label了(這樣做的好處是,在某些不需要ButtonLabel的情況下挖滤,可以節(jié)省掉創(chuàng)建它的開銷)崩溪。當然,如果需要對ButtonLabel進行操作斩松,UIButton會自動創(chuàng)建出一個Label伶唯。我們看代碼就清楚了:

//初始化時_titleRenderer是null值
void Button::setTitleText(const std::string& text)
{
    if (text == getTitleText())
    {
        //如果文本相同,則不設置
        return;
    }
    if(nullptr == _titleRenderer)
    {
        //如果未創(chuàng)建_titleRenderer惧盹,則調(diào)用createTitleRenderer創(chuàng)建之
        this->createTitleRenderer();
    }
    _titleRenderer->setString(text);
    updateContentSize();
}
//創(chuàng)建UIButton的標簽文本
void Button::createTitleRenderer()
{
   _titleRenderer = Label::create(); //ButtonLabel本質(zhì)是cc.Label
   _titleRenderer->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
   addProtectedChild(_titleRenderer, TITLE_RENDERER_Z, -1);
}

Extension


下面要說的是在UIButton使用過程中遇到的一點問題和經(jīng)驗總結(jié)乳幸,附帶幾個對ButtonLabel的方法擴展,有興趣的可以瞅瞅钧椰,有意見的也可以提出(評論區(qū)歡迎你)粹断。

別忘了ButtonLabel的本質(zhì)是cc.Label


從上面關(guān)于ButtonLabel的解釋中,我們知道嫡霞,ButtonLabel的本質(zhì)是cc.Label瓶埋,也就是說cc.Label能干的事ButtonLabel也能干,包括上面提到的幾個方法:

void Button::setTitleText(const std::string& text)
void Button::setTitleColor(const Color3B& color)
void Button::setTitleFontName(const std::string& fontName)

如果我們看源碼诊沪,不難看出养筒,這幾個方法其實就是對cc.Label的簡單封裝而已,只不過前面加了個UIButton的標簽端姚,比如:

void Button::setTitleColor(const Color3B& color)
{
        if(nullptr == _titleRenderer)
        {
          //如果不存在ButtonLabel晕粪,則創(chuàng)建之
          this->createTitleRenderer();
        }
        //cc.Label:setTextColor(Color4B(color));
        _titleRenderer->setTextColor(Color4B(color));
}

了解到這層原理后,我們就可以對ButtonLabel進行一些擴展了渐裸。

我們看UIButton.h文件巫湘,可以很清楚的看出,官方對ButtonLabel只封裝了幾個常用的方法昏鹃,按照之前的理解尚氛,我們還可以把描邊陰影洞渤、旋轉(zhuǎn)怠褐、縮放等加上,這樣就可以更充分地利用ButtonLabel了您宪。

但D卫痢5煊俊!個人不建議做這些重復的工作磷杏,因為我們已經(jīng)掌握最強大的武器--原理溜畅,那么進一步的封裝也就然并卵了。

其實不大理解為什么官方要提供好幾個操作ButtonLabel的API(可能為了方便极祸,但方便之余慈格,反而隱藏了ButtonLabel是一個cc.Label的特性)。在我看來遥金,只要保留getTitleRenderer()浴捆、setTitleText()getTitleText()等幾個常用的API基本就夠用了稿械,剩下的留給程序猿去獲得ButtonLabel选泻,再對ButtonLabel進行操作就OK了。

關(guān)于ButtonLabel奇怪的自動居中設定


有時候我們的按鈕可能是奇形怪狀的美莫,我們不能保證策劃或美術(shù)的眼光一定會保持ButtonLabel在按鈕的中央页眯。相反,它可能偏上厢呵、可能靠右窝撵、也可能需要左對齊,等等襟铭。

但是碌奉,我們通過對getTitleRenderer()獲得的ButtonLabel進行setPosition()卻驚奇地發(fā)現(xiàn)無論如何也無法滿足修改位置的需求,仿佛setPosition()失效了一般寒砖。

這是為什么赐劣?難道我們理解的原理是錯誤的嗎?
于是入撒,想不通的你只好換個方案:把ButtonLabel隱藏掉隆豹,然后手動創(chuàng)建一個Label添加到Button上椭岩,再對它進行位置操作茅逮。
對嗎?你曾經(jīng)這樣做過嗎判哥?哪怕一次献雅?

但事實證明:原理一直都在那兒,不多不少塌计,不偏不倚挺身,從未改變!
我們來看下面的幾個API就能窺見其中的根由了:

// 1锌仅、更新ButtonLabel的位置
void Button::updateTitleLocation()
{
    _titleRenderer->setPosition(_contentSize.width * 0.5f, _contentSize.height * 0.5f);
}
// 2章钾、UIButton發(fā)生變化時會調(diào)用updateTitleLocation()
void Button::onSizeChanged()
{
    Widget::onSizeChanged();
    if(nullptr != _titleRenderer)
    {
        updateTitleLocation();
    }
    _normalTextureAdaptDirty = true;
    _pressedTextureAdaptDirty = true;
    _disabledTextureAdaptDirty = true;
}
// 3墙贱、更新UIButton的ContentSize會調(diào)用onSizeChanged()
void Button::updateContentSize()
{
    if (_unifySize)
    {
        if (_scale9Enabled)
        {
ProtectedNode::setContentSize(_customSize);
        }
        else
        {
            Size s = getNormalSize();
            ProtectedNode::setContentSize(s);
        }
        onSizeChanged();
        return;
    }
    if (_ignoreSize)
    {
        this->setContentSize(getVirtualRendererSize());
    }
}

我們搜索下調(diào)用updateContentSize()的地方,就會驚奇地發(fā)現(xiàn)贱傀,幾乎對ButtonLabel操作的最后都會調(diào)用updateContentSize()惨撇!難怪盡管我們把ButtonLabel的position屬性設置到了十萬八千里,ButtonLabel依然盤踞中原府寒,風雨不動安如山魁衙!因為系統(tǒng)把它自動居中了,只要它有些許變化株搔,系統(tǒng)就會把它自動居中剖淀,自動居中了啊纤房!

對此奇葩的設定纵隔,我只想說:這!TM帆卓!太巨朦!不!科剑令!學糊啡!了!

這下我們知道這是系統(tǒng)搞的鬼了吁津,那么有什么辦法解決這個問題呢棚蓄?答案當然是肯定的。
既然updateContentSize()就免不了updateTitleLocation()碍脏,那么只要修改ButtonLabel最后的位置不就萬事大吉了嗎梭依?

為達此目的,我們需要耍點手段典尾,叫做中心偏移量役拴。我們把中心偏移量分為兩個部分,分別是相對x軸的偏移_titleOffsetX和相對y軸的偏移_titleOffsetY钾埂,并把他們設置為UIButton的固有屬性河闰。當然,它們的初始值應該都是0褥紫。

Notes:_titleOffsetX_titleOffsetY是相對按鈕中點位置的偏移量姜性。

這樣,當我們需要更新ButtonLabel位置的時候髓考,它們就可以發(fā)揮作用了部念。于是updateTitleLocation()就可以改成這樣:

void Button::updateTitleLocation()
{
    _titleRenderer->setPosition(_contentSize.width * 0.5f + _titleOffsetX, _contentSize.height * 0.5f + _titleOffsetY);
}

嗯,這樣開頭和結(jié)尾我們都完成了,那么只剩下操作過程中的偏移修改了儡炼。我們創(chuàng)建一個新的接口妓湘,就叫setTitleOffset()吧,對乌询,它應該能接收x多柑、y軸兩個偏移量作為輸入?yún)?shù),然后賦值給_titleOffsetX_titleOffsetY楣责,最后再更新一下ButtonLabel的位置竣灌,基本就大功告成了。嗯秆麸,它的最終模樣可能是這樣的:

void Button::setTitleOffset(float offsetX, float offsetX){
    _titleOffsetX = offsetX;
    _titleOffsetY = offsetX;
    updateTitleLocation();
}

當然初嘹,除此之外,你還可以根據(jù)自己的理解進行改良和擴展沮趣。比如屯烦,我希望能夠通過setPosition()直接對ButtonLabel起作用,我就可以這樣做:

void Button::setTitlePosition(float x, float y){
    if(_titleRenderer == nullptr){
        return;
    }
    Vec2 vec = _titleRenderer->getPosition();
    _titleOffsetX = x - vec.x;
    _titleOffsetY = y - vec.y;
    updateTitleLocation();
}

怎么樣房铭?是不是很簡單驻龟?接下來,感興趣的同學不妨動手試試擴展ButtonLabel使其支持左對齊缸匪、右對齊吧翁狐。

用lua作為主要開發(fā)語言的同學還可以把上面完成的兩個接口綁定到lua,這樣就更方便使用啦凌蔬!

Conclusion

有時候露懒,雖然只是幾行代碼,卻極大的提高了開發(fā)效率砂心。
有時候懈词,雖然只是一點好奇,卻可以讓你窺見真知辩诞。
有時候坎弯,不妨挖幾個腦洞,自己填填坑吧译暂,說不定就有意想不到的收獲了抠忘。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市秧秉,隨后出現(xiàn)的幾起案子褐桌,更是在濱河造成了極大的恐慌衰抑,老刑警劉巖象迎,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡砾淌,警方通過查閱死者的電腦和手機啦撮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來汪厨,“玉大人赃春,你說我怎么就攤上這事〗俾遥” “怎么了织中?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長衷戈。 經(jīng)常有香客問我狭吼,道長,這世上最難降的妖魔是什么殖妇? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任刁笙,我火速辦了婚禮,結(jié)果婚禮上谦趣,老公的妹妹穿的比我還像新娘疲吸。我一直安慰自己,他們只是感情好前鹅,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布摘悴。 她就那樣靜靜地躺著,像睡著了一般舰绘。 火紅的嫁衣襯著肌膚如雪烦租。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天除盏,我揣著相機與錄音叉橱,去河邊找鬼。 笑死者蠕,一個胖子當著我的面吹牛窃祝,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播踱侣,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼粪小,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了抡句?” 一聲冷哼從身側(cè)響起探膊,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎待榔,沒想到半個月后逞壁,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體流济,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年腌闯,在試婚紗的時候發(fā)現(xiàn)自己被綠了绳瘟。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡姿骏,死狀恐怖糖声,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情分瘦,我是刑警寧澤蘸泻,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站嘲玫,受9級特大地震影響蟋恬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜趁冈,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一歼争、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧渗勘,春花似錦沐绒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至取刃,卻和暖如春蹋肮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背璧疗。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工坯辩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人崩侠。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓漆魔,卻偏偏與公主長得像,于是被迫代替她去往敵國和親却音。 傳聞我的和親對象是個殘疾皇子改抡,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件系瓢、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,104評論 4 62
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,145評論 25 707
  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案阿纤? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標簽默認的外補...
    _Yfling閱讀 13,754評論 1 92
  • 每次無聊發(fā)呆的時候,都覺得自己在浪費時間夷陋,浪費生命欠拾。 然后不知覺就會問自己胰锌,自己到底是什么樣的一個人,又到底想成為...
    回希閱讀 206評論 2 2
  • 初冬的午后爹谭,我和老公漫步走在街區(qū)的小路上枷邪,溫暖的陽光照在身上,很愜意诺凡。 從一戶人家的院子經(jīng)過時东揣,老公突然說:“刺猬...
    飄于長白云之鄉(xiāng)閱讀 352評論 0 2