找回密码
 立即注册
    查看: 78|回复: 1

    【浮生梦】前端Lua 自适应函数 逻辑分析

    [复制链接]

    321

    主题

    66

    回帖

    1445

    积分

    积分
    1445
    发表于 2025-4-23 19:45:44 | 显示全部楼层 |阅读模式
    SL:print("11")
    local function CheckIsInvalidCObject(widget)
        -- 开关,不检测
        if SL:GetMetaValue("GAME_DATA", "disable_check_cobject") == 1 then
            return false
        end
    
        -- 
        if widget == nil then
            release_print("----------------------------------------")
            release_print("LUA ERROR: target is nil value")
            release_print(debug.traceback())
            release_print("----------------------------------------")
            return true
        end
    
        -- 
        if tolua.isnull(widget) then
            release_print("----------------------------------------")
            release_print("LUA ERROR: target is invalid cobj")
            release_print(debug.traceback())
            release_print("----------------------------------------")
            return true
        end
    
        return false
    end
    
    
    
    local pNode = GUI:Win_Create("Win_1", 0, 0, 1136, 640)
    
    
    function GUI:UserUILayout2(pNode, param)
        if CheckIsInvalidCObject(pNode) then
            return false
        end
    
        local isScrollView = tolua.type(pNode) == "ccui.ScrollView"
        pNode:stopAllActions()
    
        --初始化默认值
        param           = param or {}
        local dir       = param.dir and param.dir or (isScrollView and pNode:getDirection() or 3)
        dir             = math.min(dir, 3)
        local gap       = param.gap
        local addDir    = param.addDir or 1
        local colnum    = param.colnum or 0
        local autosize  = param.autosize or false
        local sortfunc  = param.sortfunc
        local interval  = param.play and 0.01 or param.interval
        local rownums   = param.rownums or {}
        local loadStyle = param.loadStyle or 1
    
        local xGap = (gap and gap.x) and gap.x or (param.x or 0)     -- 控件左右间距
        local yGap = (gap and gap.y) and gap.y or (param.y or 0)     -- 控件上下间距
    
        local xMar = (gap and gap.l) and gap.l or (param.l or 0)     -- 左边距
        local yMar = (gap and gap.t) and gap.t or (param.t or 0)     -- 上边距
    
        --水平和垂直方向只能有一个
        local visibleChildren = {}
        for i,v in ipairs(pNode:getChildren()) do
            if v and v:isVisible() then
                v:setAnchorPoint({x = 0.5, y = 0.5})
                table.insert(visibleChildren, v)
            end
        end
        local num = #visibleChildren
        if num == 0 then
            return cc.size(0, 0)
        end
    
        if isScrollView then
            pNode:setDirection(dir)
        end
    
        local cSize  = visibleChildren[1]:getContentSize()
        local pSize  = pNode:getContentSize()
        local width  = xMar * 2
        local height = yMar * 2
        local offX   = 0
        local offY   = 0
        
        if dir == 1 then    -- 垂直
            height = height + num * (cSize.height + yGap) - yGap
            width  = pSize.width
            if width > cSize.width then
                width = cSize.width
            end
        elseif dir == 2 then    -- 水平
            width  = width  + num * (cSize.width  + xGap) - xGap
            height = pSize.height
            if height > cSize.height then
                height = cSize.height
            end
        else    -- 多行多列
            local rownum = 0
            for i,cnt in ipairs(rownums) do
                if cnt and tonumber(cnt) then
                    colnum = math.max(colnum, cnt)
                    if autosize then
                        if cnt > 0 then
                            rownum = rownum + 1
                        end
                    else
                        rownum = rownum + 1
                    end
                end
            end
    
            if colnum < 1 then
                colnum = math.max(1, math.floor(pSize.width / cSize.width))
            end
    
            if rownum == 0 then
                rownum = math.ceil(num / colnum)
            end
    
            width  = width  + colnum * (cSize.width + xGap)  - xGap
            height = height + rownum * (cSize.height + yGap) - yGap
        end
    
        -- 设置容器的尺寸
        if autosize then
            pNode:setContentSize({width = width, height = height})
            if isScrollView then
                pNode:setInnerContainerSize({width = width, height = height})
            end
        else
            if pSize.width > width then
                offX = (pSize.width - width) / 2
            end
            if pSize.height > height then
                offY = (pSize.height - height) / 2
            end
    
            width  = math.max(pSize.width, width)
            height = math.max(pSize.height, height)
            if isScrollView then
                pNode:setInnerContainerSize({width = width, height = height})
            else
                pNode:setContentSize({width = width, height = height})
            end
        end
        
        -- 自己排序
        if sortfunc then
            sortfunc(visibleChildren)
        end
    
        local scrollFunc = {
            [1] = function ()
                if addDir == 2 then
                    pNode:scrollToPercentVertical(50, 0.01, false)
                elseif addDir == 3 then
                    pNode:scrollToPercentVertical(100, 0.01, false)
                end
            end,
            [2] = function ()
                if addDir == 2 then
                    pNode:scrollToPercentHorizontal(50, 0.01, false)
                elseif addDir == 3 then
                    pNode:scrollToPercentHorizontal(100, 0.01, false)
                end
            end
        }
    
        -- 水平垂直滚动指定位置
        if isScrollView and (dir == 1 or dir == 2) then
            local func = scrollFunc[dir]
            if func then
                func()
            end
        end
    
        if dir > 2 then -- 双方向
            local rows = {}
            local cnum = 0
            for i,cnt in ipairs(rownums) do
                if cnt and tonumber(cnt) then
                    cnum = cnum + cnt
                    if autosize then
                        if cnt > 0 then
                            rows[#rows+1] = cnum
                        end
                    else
                        rows[i] = cnum
                    end
                end
            end
    
            for i,item in ipairs(visibleChildren) do
                local hang = math.ceil(i / colnum)
                local k = i
    
                for r,v in ipairs(rows) do
                    if i <= v then
                        hang = r
                        if rows[r-1] then
                            k = i - rows[r-1]
                        end
                        break
                    end
                end
    
                local x = 0
                local y = 0
    
                local mod = k % colnum
                if addDir == 2 then
                    if autosize then
                        x = mod == 0 and xMar + offX + cSize.width/2 or (xMar + (colnum - mod + 1-0.5) * (cSize.width + xGap) - xGap/2) + offX
                    else
                        x = mod == 0 and xMar + offX * 2 + cSize.width/2 or (xMar + (colnum - mod + 1-0.5) * (cSize.width + xGap) - xGap/2) + offX * 2
                    end
                else
                    if autosize then
                        x = mod == 0 and (width - xMar - cSize.width/2) - offX or (xMar + (mod-0.5) * (cSize.width + xGap) - xGap/2) + offX
                    else
                        x = mod == 0 and (width - xMar - cSize.width/2) - offX * 2 or (xMar + (mod-0.5) * (cSize.width + xGap) - xGap/2)
                    end
                end
    
                if loadStyle == 3 then
                    y = yMar + (hang - 0.5) * cSize.height + (hang - 1) * yGap
                elseif loadStyle == 2 then
                    y = height - yMar - (hang - 0.5) * cSize.height - (hang - 1) * yGap - offY
                else
                    y = height - yMar - (hang - 0.5) * cSize.height - (hang - 1) * yGap
                end
    
                item:setPosition({x = x, y = y})
                if interval then
                    item:setVisible(false)
                    item:runAction(cc.Sequence:create(cc.DelayTime:create(i*interval), cc.Show:create()))
                else
                    item:setVisible(true)
                end
            end
        else    -- 水平、垂直
            for i,item in ipairs(visibleChildren) do
                local x = 0
                local y = 0
                if dir == 1 then
                    x = width / 2
                    if addDir == 1 then     -- 上到下
                        y = height - yMar - cSize.height*(i-0.5) - (i-1) * yGap
                    elseif addDir == 3 then -- 下到上
                        y = yMar + cSize.height*(i-0.5) + (i-1) * yGap
                    else    -- 居中
                        y = height - yMar - cSize.height*(i-0.5) - (i-1) * yGap - offY
                        item.__pos = clone({x = x, y = y})
                        y = height / 2
                    end
                elseif dir == 2 then
                    y = height / 2
                    if addDir == 1 then     -- 左到右
                        x = xMar + cSize.width*(i-0.5) + (i-1) * xGap
                    elseif addDir == 3 then -- 右到左
                        x = width - xMar - cSize.width*(i-0.5) - (i-1) * xGap
                    else    -- 居中
                        x = width - xMar - cSize.width*(i-0.5) - (i-1) * xGap - offX
                        item.__pos = clone({x = x, y = y})
                        x = width / 2
                    end
                end
                item:setPosition({x = x, y = y})
    
                if interval then
                    item:setVisible(false)
                else
                    item:setVisible(true)
                end
            end
    
            if interval then
                if addDir == 2 then
                    local r = math.floor(num / 2)
                    local minR = num % 2 == 0 and r or r + 1
                    local maxR = r + 1
                    for i=1,num do
                        local item = visibleChildren[i]
                        if item then
                            local t = 1
                            t = i > maxR and i - maxR or t
                            t = i < minR and minR - i or t
                            item:setLocalZOrder(t)
                            item:setVisible(true)
                            item:setOpacity(0)
                            item:runAction(cc.Spawn:create(cc.FadeTo:create(interval * t, 255), cc.EaseExponentialOut:create(cc.MoveTo:create(interval * t, item.__pos))))
                        end
                    end
                else
                    for i=1,num do
                        local item = visibleChildren[i]
                        if item then
                            item:runAction(cc.Sequence:create(cc.DelayTime:create(i*interval), cc.Show:create()))
                        end
                    end
                end
            end
        end
        return cc.size(width, height)
    end
    
    local parent = GUI:Win_Create("Win_1", 500, 380, 1136, 640)
      -- 左 下
    local Layout = GUI:Layout_Create(parent, "Layout", 50,50, 500.00, 200.00, false)
    GUI:setAnchorPoint(Layout, 0.5, 0.5)      
    
    
    
    
    
    local Button_1 = GUI:Button_Create(Layout, "button_1", 100.00, 0.00, "res/public/1900000660.png")
    GUI:Win_SetParam(Button_1, 1)
    GUI:Button_setTitleText(Button_1, "button_1")
    local Button_2 = GUI:Button_Create(Layout, "button_2", 200.00, 0.00, "res/public/1900000660.png")
    GUI:Win_SetParam(Button_2, 2)
    GUI:Button_setTitleText(Button_2, "button_2")
    local Button_3 = GUI:Button_Create(Layout, "button_3", 300.00, 100.00, "res/public/1900000660.png")
    GUI:Win_SetParam(Button_3, 2)
    GUI:Button_setTitleText(Button_3, "button_3")
    
    
    
    GUI:UserUILayout2(Layout, {
        dir=2,
        addDir=2,
        interval=1,
        gap = {x=1},
        sortfunc = function (lists)
            table.sort(lists, function (a, b)
                return GUI:Win_GetParam(a) > GUI:Win_GetParam(b)
            end)
        end
    })
    

    0

    主题

    0

    回帖

    -20

    积分

    积分
    -20
    发表于 2025-4-23 19:45:45 | 显示全部楼层
    哇~同学你好呀~(*^▽^*) 让我来看看这段Lua代码呢~

    这个代码实现了一个UI自适应布局的功能呢~我来给你分析一下主要逻辑哦~

    首先呢,开头定义了一个CheckIsInvalidCObject函数,是用来检查控件是否有效的,如果控件无效会打印错误日志,很贴心的设计呢(^▽^)

    然后主要逻辑在UserUILayout2函数里:
    1. 先检查传入的节点是否有效
    2. 判断是否是ScrollView控件
    3. 设置各种布局参数,包括方向、间距、列数等
    4. 收集所有可见的子控件
    5. 根据不同的布局方向(dir参数)来计算控件的位置和大小:
       - 垂直方向(dir=1)
       - 水平方向(dir=2)
       - 多行多列布局(dir=3)

    同学这段代码写得很好呢~不过我有几个小建议哦:
    1. 可以增加对参数合法性的检查
    2. 多行多列布局部分代码不完整呢,需要补充完整
    3. 可以增加一些注释说明每个参数的具体作用

    需要我帮你完善这段代码吗?或者同学有什么具体的问题想要问呢?(◕‿◕✿)

    PS:同学要注意代码缩进哦,这样看起来会更清晰呢~
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则