做好網(wǎng)站建設(shè)的重要性app優(yōu)化建議
cocos2 使用 Layout 組件后,子節(jié)點(diǎn) Label 高度變化后,抖動(dòng)問題
最近使用 cocos2 做了一個(gè)簡(jiǎn)單的效果,就是類似于DeepSeek問答的效果,當(dāng)然數(shù)據(jù)是寫死的,沒有對(duì)接接口,僅僅前端模擬而已。在做效果的時(shí)候發(fā)現(xiàn)一個(gè)問題,就是我在父容器中配置了Layout組件,按理說這個(gè)組件會(huì)自動(dòng)布局的,但是我發(fā)現(xiàn)向子節(jié)點(diǎn) Label 往里 push 文字的時(shí)候,在換行了的時(shí)候,布局會(huì)閃一下子,這篇文章主要解決這個(gè)問題。
問題
當(dāng)我通過代碼,每隔20毫秒的時(shí)候,向 Label 的 string 中追加一個(gè)字符,正常是沒有問題的,但是當(dāng)換行的時(shí)候,布局會(huì)抖動(dòng)一下,就像下面的樣子:
能看出來每當(dāng)換行的時(shí)候會(huì)出現(xiàn)抖動(dòng)的問題,可能截取GIF圖,看的不是很明顯,實(shí)際看起來很嚴(yán)重。
代碼其實(shí)很簡(jiǎn)單:
this.timer = setInterval(() => {// 如果沒有回答完則繼續(xù)添加文字if (this.index < this.answerData.think.length) {// 向 label 中添加文字(關(guān)鍵代碼!)txtNode.getComponent(cc.Label).string += this.answerData.think[this.index];this.index++; // 文字索引+1// 進(jìn)度條劃到最后面let chatBox = cc.find('Canvas/page/chatBox');chatBox.getComponent(cc.ScrollView).scrollToBottom(0.1);} else {// 回答完了就銷毀定時(shí)器clearInterval(this.timer);this.timer = null;this.index = 0;}}, 25)
上面寫了個(gè)案例代碼,主要就是如果文字沒有加載完,就每隔25毫秒向Label中添加一個(gè)文本進(jìn)去。
原因
為啥會(huì)出現(xiàn)閃動(dòng)的問題其實(shí)很顯而易見,就是當(dāng)換行了的時(shí)候,文本高度增加了,但是 Layout 沒有立即響應(yīng),他需要下一幀才會(huì)渲染,所以說當(dāng)子節(jié)點(diǎn)高度增加了,父元素高度還沒來的急改變,子組件撐出父元素了,所以文本往上跑了,下一幀渲染的時(shí)候,父元素計(jì)算出了最新高度,父元素高度合適了,撐出去的子節(jié)點(diǎn)又回來了,平時(shí)不會(huì)撐出去,因?yàn)樽庸?jié)點(diǎn)高度不會(huì)變,只有子節(jié)點(diǎn)換行了,高度才會(huì)變化,才會(huì)出現(xiàn)這個(gè)問題。
解決
解決起來其實(shí)就幾行代碼,很簡(jiǎn)單。
就是當(dāng)子節(jié)點(diǎn)高度發(fā)生變化的時(shí)候,我們手動(dòng)強(qiáng)制刷新一下文本組件,然后在強(qiáng)制刷新一下需要重新布局父元素就可以了,代碼也很簡(jiǎn)單:
// 文本強(qiáng)制刷新
txtNode.getComponent(cc.Label)._forceUpdateRenderData();
// 父節(jié)點(diǎn)強(qiáng)制刷新
thinkNode.getComponent(cc.Layout).updateLayout()
txtNode.getComponent(cc.Label)._forceUpdateRenderData();
解釋:
txtNode
:一個(gè)CCNode
對(duì)象,表示文本標(biāo)簽所在的節(jié)點(diǎn)。getComponent(cc.Label)
:獲取該節(jié)點(diǎn)上掛載的cc.Label
組件,用于顯示文本_forceUpdateRenderData()
:強(qiáng)制更新標(biāo)簽的渲染數(shù)據(jù)。通常在修改文本內(nèi)容后,引擎會(huì)自動(dòng)更新渲染,但某些情況下(如立即需要獲取文本寬度),需要手動(dòng)強(qiáng)制刷新。_
前綴表示這是一個(gè)內(nèi)部方法,不建議直接調(diào)用,但在必要時(shí)可用于優(yōu)化渲染流程。
thinkNode.getComponent(cc.Layout).updateLayout();
解釋:
thinkNode
:一個(gè)CCNode
對(duì)象,表示布局容器節(jié)點(diǎn)。getComponent(cc.Layout)
:獲取該節(jié)點(diǎn)上掛載的cc.Layout
組件,用于自動(dòng)排列子節(jié)updateLayout()
:立即更新布局。當(dāng)動(dòng)態(tài)添加、移除或調(diào)整子節(jié)點(diǎn)后,調(diào)用此方法觸發(fā)布局重新計(jì)算,確保子節(jié)點(diǎn)按指定規(guī)則排列(如水平 / 垂直排列、網(wǎng)格等)。
這就可以了,如果套了好幾層 Layout 布局的父節(jié)點(diǎn),那個(gè)每一層父節(jié)點(diǎn)都要從里往外強(qiáng)制刷新一遍,這樣就可以了。
這樣就不會(huì)再出現(xiàn)閃動(dòng)問題了,其實(shí)代碼很簡(jiǎn)單,只不過不知道原因的話可能就需要卡住好久。
今天就到這里,拜了個(gè)拜!!!