cocos2d-x的lua腳本加載CocostudioUI兩種方式


前言

   當前版本使用的是quick cocos2dx lua 3.3。UI使用cocostudio編輯器1.6.0。我們在程序里面可以使用兩種方式進行解析UI。開始的時候用的是quick的方法,

結果遇到了坑(百分比控件布局CCSUILoader.lua在解析時,沒有對百分比進行處理,結果方案可以自己加上去)。

特別提醒:

  如果在quick中使用源生的解析方案(c++),可能出現觸摸bug。因為在quick中自己實現了新的觸摸機制(詳情請參考LuaTouchEventManager.h 中具體的實現)

所有的觸摸級別都是0,根據渲染層級處理事件

  建議:在項目實際開發中,應該自己封裝一層,方便修改。

一.quick使用cocostudio

 1.加載

local uiNode = cc.uiloader:load("TestUI.json")
self:addChild(uiNode)
cc.uiloader:load("XXXX.json") 后面的參數是你的cocostudio導出文件,注意路徑問題

 2.讀取控件

  在程序中獲取控件的方法,我們可以看下 framework/cc/uiloader/uiloader.lua, (CCSUILoader.lua文件可以看下,講具體怎么實現的)

-- @module uiloader

--[[--

初始化 cc.uiloader,並提供對外統一接口

cc.uiloader 可以將CCS導出的json文件用quick的純lua控件構建出UI布局

]]

local UILoaderUtilitys = import(".UILoaderUtilitys")
local uiloader = class("uiloader")
local CCSUILoader = import(".CCSUILoader")
local CCSSceneLoader = import(".CCSSceneLoader")

-- start --

--------------------------------
-- 初始化 cc.uiloader,並提供對外統一接口
-- @function [parent=#uiloader] new

-- end --

function uiloader:ctor()
end

-- start --

--------------------------------
-- 解析json文件
-- @function [parent=#uiloader] load
-- @param string jsonFile 要解析的json文件
-- @param table params 解析參數
-- @return node#node  解析后的布局

-- end --

function uiloader:load(jsonFile, params)
    local json
    if not params or not params.bJsonStruct then
        local pathInfo = io.pathinfo(jsonFile)
        if ".csb" == pathInfo.extname then
            return cc.CSLoader:getInstance():createNodeWithFlatBuffersFile(jsonFile)
        else
            json = self:loadFile_(jsonFile)
        end
    else
        json = jsonFile
    end
    if not json then
        print("uiloader - load file fail:" .. jsonFile)
        return
    end

    local node

    if self:isScene_(json) then
        node, w, h = CCSSceneLoader:load(json, params)
    else
        node, w, h = CCSUILoader:load(json, params)
    end

    UILoaderUtilitys.clearPath()

    return node, w, h
end

-- start --

--------------------------------
-- 按tag查找布局中的結點
-- @function [parent=#uiloader] seekNodeByTag
-- @param node parent 要查找布局的結點
-- @param number tag 要查找的tag
-- @return node#node 

-- end --

function uiloader:seekNodeByTag(parent, tag)
    if not parent then
        return
    end

    if tag == parent:getTag() then
        return parent
    end

    local findNode
    local children = parent:getChildren()
    local childCount = parent:getChildrenCount()
    if childCount < 1 then
        return
    end
    for i=1, childCount do
        if "table" == type(children) then
            parent = children[i]
        elseif "userdata" == type(children) then
            parent = children:objectAtIndex(i - 1)
        end

        if parent then
            findNode = self:seekNodeByTag(parent, tag)
            if findNode then
                return findNode
            end
        end
    end

    return
end

-- start --

--------------------------------
-- 按name查找布局中的結點
-- @function [parent=#uiloader] seekNodeByName
-- @param node parent 要查找布局的結點
-- @param string name 要查找的name
-- @return node#node 

-- end --

function uiloader:seekNodeByName(parent, name)
    if not parent then
        return
    end

    if name == parent.name then
        return parent
    end

    local findNode
    local children = parent:getChildren()
    local childCount = parent:getChildrenCount()
    if childCount < 1 then
        return
    end
    for i=1, childCount do
        if "table" == type(children) then
            parent = children[i]
        elseif "userdata" == type(children) then
            parent = children:objectAtIndex(i - 1)
        end

        if parent then
            if name == parent.name then
                return parent
            end
        end
    end

    for i=1, childCount do
        if "table" == type(children) then
            parent = children[i]
        elseif "userdata" == type(children) then
            parent = children:objectAtIndex(i - 1)
        end

        if parent then
            findNode = self:seekNodeByName(parent, name)
            if findNode then
                return findNode
            end
        end
    end

    return
end

-- start --

--------------------------------
-- 按name查找布局中的結點
-- 與seekNodeByName不同之處在於它是通過node的下子結點表來查詢,效率更快
-- @function [parent=#uiloader] seekNodeByNameFast
-- @param node parent 要查找布局的結點
-- @param string name 要查找的name
-- @return node#node 

-- end --

function uiloader:seekNodeByNameFast(parent, name)
    if not parent then
        return
    end

    if not parent.subChildren then
        return
    end

    if name == parent.name then
        return parent
    end

    local findNode = parent.subChildren[name]
    if findNode then
        -- find
        return findNode
    end

    for i,v in ipairs(parent.subChildren) do
        findNode = self:seekNodeByName(v, name)
        if findNode then
            return findNode
        end
    end

    return
end

-- start --

--------------------------------
-- 根據路徑來查找布局中的結點
-- @function [parent=#uiloader] seekNodeByPath
-- @param node parent 要查找布局的結點
-- @param string path 要查找的path
-- @return node#node 

-- end --

function uiloader:seekNodeByPath(parent, path)
    if not parent then
        return
    end

    local names = string.split(path, '/')

    for i,v in ipairs(names) do
        parent = self:seekNodeByNameFast(parent, v)
        if not parent then
            return
        end
    end

    return parent
end

-- start --

--------------------------------
-- 查找布局中的組件結點
-- @function [parent=#uiloader] seekComponents
-- @param node parent 要查找布局的結點
-- @param string nodeName 要查找的name
-- @param number componentIdx 在查找組件在它的直接父結點的位置
-- @return node#node 


--[[--

查找布局中的組件結點

~~~ lua

-- "hero" 是結點名稱
-- 1 是 "hero"這個結點下的第一個組件
local hero = cc.uiloader:seekComponents(parentNode, "hero", 1)

~~~

]]
-- end --

function uiloader:seekComponents(parent, nodeName, componentIdx)
    local node = self:seekNodeByName(parent, nodeName)
    if not node then
        return
    end
    node = self:seekNodeByName(node, "Component" .. componentIdx)
    return node
end

-- private
function uiloader:loadFile_(jsonFile)
    local fileUtil = cc.FileUtils:getInstance()
    local fullPath = fileUtil:fullPathForFilename(jsonFile)

    local pathinfo  = io.pathinfo(fullPath)
    UILoaderUtilitys.addSearchPathIf(pathinfo.dirname)

    local jsonStr = fileUtil:getStringFromFile(fullPath)
    local jsonVal = json.decode(jsonStr)

    return jsonVal
end

function uiloader:isScene_(json)
    if json.components then
        return true
    else
        return false
    end
end

return uiloader

 

  button我們肯定會和他打交道的,這里我說下。在CCSUILoader.lua中我們可以看到,這里加載的是quick自己的button控件

如果我們沒有在cocostudio中設置button的選中和禁止圖片,這里點擊是沒有任何效果的,而使用c++時,會點擊方法效果,我們可以根據自己的需求做相應修改

function CCSUILoader:createButton(options)
    local node = cc.ui.UIPushButton.new(self:getButtonStateImages(options),
        {scale9 = options.scale9Enable,
        flipX = options.flipX,
        flipY = options.flipY})

    if options.opacity then
        node:setCascadeOpacityEnabled(true)
        node:setOpacity(options.opacity)
    end
    if options.text then
        node:setButtonLabel(
            cc.ui.UILabel.new({text = options.text,
                size = options.fontSize,
                color = cc.c3b(options.textColorR, options.textColorG, options.textColorB)}))
    end
    if not options.ignoreSize then
        node:setButtonSize(options.width, options.height)
    end
    node:align(self:getAnchorType(options.anchorPointX or 0.5, options.anchorPointY or 0.5),
        options.x or 0, options.y or 0)

    return node
end

下面是一個讀取按鈕的例子:

 
         
local button = cc.uiloader:seekNodeByPath(self.uiNode, buttonName)
if button ~= nil then 
   button:addButtonClickedEventListener(function(...)
   self:onCickSublistButton()
end)
 

二.cocos2dx自帶使用cocostudio

  我覺得這個還是比較好的,因為觸控一直在更新完善。而quick目前是沒有在維護。

1.加載

local uiNode = ccs.GUIReader:getInstance():widgetFromJsonFile("Test.json")
uiNode:addTo(self)

可以參考GUIReader.lua 或者\cocos\editor-support\cocostudio CCSGUIReader.h (GUIReader.lua 是c++綁定到lua 時生成的api)

 

 2.讀取控件

  這里控件的解析我們使用的是Helper ,可以參考 api Helper.lua 和具體的c++類Helper.h

--------------------------------
-- @module Helper
-- @parent_module ccui

--------------------------------
-- brief Get a UTF8 substring from a std::string with a given start position and length<br>
-- Sample:  std::string str = "中國中國中國";  substr = getSubStringOfUTF8String(str,0,2) will = "中國"<br>
-- param start The start position of the substring.<br>
-- param length The length of the substring in UTF8 count<br>
-- return a UTF8 substring
-- @function [parent=#Helper] getSubStringOfUTF8String 
-- @param self
-- @param #string str
-- @param #unsigned long start
-- @param #unsigned long length
-- @return string#string ret (return value: string)
        
--------------------------------
-- 
-- @function [parent=#Helper] changeLayoutSystemActiveState 
-- @param self
-- @param #bool bActive
        
--------------------------------
-- 
-- @function [parent=#Helper] seekActionWidgetByActionTag 
-- @param self
-- @param #ccui.Widget root
-- @param #int tag
-- @return Widget#Widget ret (return value: ccui.Widget)
        
--------------------------------
-- Finds a widget whose name equals to param name from root widget.<br>
-- param root      widget which will be seeked.<br>
-- name             name value.<br>
-- return finded result.
-- @function [parent=#Helper] seekWidgetByName 
-- @param self
-- @param #ccui.Widget root
-- @param #string name
-- @return Widget#Widget ret (return value: ccui.Widget)
        
--------------------------------
-- Finds a widget whose tag equals to param tag from root widget.<br>
-- param root      widget which will be seeked.<br>
-- tag             tag value.<br>
-- return finded result.
-- @function [parent=#Helper] seekWidgetByTag 
-- @param self
-- @param #ccui.Widget root
-- @param #int tag
-- @return Widget#Widget ret (return value: ccui.Widget)
        
--------------------------------
-- 
-- @function [parent=#Helper] doLayout 
-- @param self
-- @param #cc.Node rootNode
        
return nil

下面是button的例子:

local button = ccui.Helper:seekWidgetByName(self.uiNode, buttonName)
function CampMainlayer:initButton()
    local function touchEvent(sender,event)
         if event == ccui.TouchEventType.ended then
            if sender ~= nil then
                local tag = sender:getTag()-1000
                --TODO:操作
            end    
        end
    end
    for i=1,3 do
        local buttonName = "Button_"..i
        local button = ccui.Helper:seekWidgetByName(self.uiNode, buttonName)
        if button ~= nil then 
            button:addTouchEventListener(touchEvent)
            button:setTag(1000+i)
        end
    end
end

注意 ccui.TouchEventType.ended  這是在 cocos.ui.GuiConstants中,所以我們想用這些的話,需要 require("cocos.ui.GuiConstants")。

  我們在實際的項目開發中,肯定會遇到很多問題,當然,遇到問題我們可以在網上找,但是並不是所有的問題都能找到,所以,自己動手解決問題的能力很重要,

對於我們來說,去看源碼,看具體的實現,就能很快找到解決問題的方式。

如果有什么問題,請加我的QQ776274781,或者群:102349463 。大家一起學習。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM