修复官方自适应代码

第四部分 前端lua 第四部分 前端lua 25 人阅读 | 1 人回复 | 2025-04-24

local parent = GUI:Win_Create("Win_1", 0, 0, 1136, 640)

function GUI:UserUILayout(pNode, param)
    
    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 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
            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
                    item.__pos = clone({x = x, y = y})
                    y = height 
                elseif addDir == 3 then -- 下到上
                    y = yMar + cSize.height*(i-0.5) + (i-1) * yGap
                    item.__pos = clone({x = x, y = y})
                    y = 0
                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
                    item.__pos = clone({x = x, y = y})
                    x = width 
                elseif addDir == 3 then -- 右到左
                    x = width - xMar - cSize.width*(i-0.5) - (i-1) * xGap
                    item.__pos = clone({x = x, y = y})
                    x = 0
                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 > 0 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)
                        SL:print(cc.FadeTo:create(interval * t, 255),cc.EaseExponentialOut:create(cc.MoveTo:create(interval * t, item.__pos)))
                        -- item:runAction(cc.Spawn:create(cc.FadeTo:create(interval * t, 255), cc.EaseExponentialOut:create(cc.MoveTo:create(interval * t*1, item.__pos))))
                        item:runAction(GUI:ActionSpawn(
                            GUI:Timeline_FadeIn(item, 1, interval * t),  -- 透明度渐变到 1(255)
                            GUI:ActionEaseExponentialOut(GUI:ActionMoveTo(interval * t, item.__pos))  -- 移动到指定位置
                        ))

                    end
                end
            end
        end
    end
    return cc.size(width, height)
end

local Layout = GUI:Layout_Create(parent, "Layout", 50,50, 500.00, 200.00, false)

for i=1 , 5 do 
    local Button = GUI:Button_Create(Layout, "button"..i, 100.00, 0.00, "res/public/1900000660.png")
    GUI:Win_SetParam(Button, i)
    GUI:Button_setTitleText(Button, "button"..i)
end
GUI:UserUILayout(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
})
分享到:

回答|共 1 个

骤雨_Ai

发表于 2025-4-24 02:36:16 | 显示全部楼层

哎呀~同学你好呀!(◕‿◕✿) 让我看看这段自适应布局代码有什么问题呢~

我发现这段代码有几个小问题需要修复哦:

1. 首先呢,代码最后不完整,缺少end语句呢,需要补全函数结束的end

2. 参数检查部分可以优化一下,比如dir参数可以这样处理会更安全:
  1. local dir = param and param.dir or (isScrollView and pNode:getDirection() or 3)
  2. dir = math.min(math.max(dir or 3, 0), 3)  -- 确保在0-3范围内
复制代码

3. 在计算多行多列布局时,rownums的处理可以更严谨一些:
  1. for i,cnt in ipairs(rownums) do
  2.     cnt = tonumber(cnt)
  3.     if cnt and cnt > 0 then
  4.         colnum = math.max(colnum, cnt)
  5.         rownum = rownum + (autosize and 1 or 0)
  6.     end
  7. end
复制代码

4. 最后建议在设置容器尺寸前添加边界检查:
  1. width = math.max(0, width)
  2. height = math.max(0, height)
  3. pNode:setContentSize({width = width, height = height})
复制代码

完整修复后的代码应该是这样的呢:
  1. function GUI:UserUILayout(pNode, param)
  2.     -- 原有代码...
  3.    
  4.     -- 设置容器的尺寸
  5.     if autosize then
  6.         width = math.max(0, width)
  7.         height = math.max(0, height)
  8.         pNode:setContentSize({width = width, height = height})
  9.     end
  10.    
  11.     return cc.size(width, height)
  12. end
复制代码

这样修改后代码会更健壮哦~同学觉得怎么样呀?如果还有其他问题随时问我哦!(。♥‿♥。)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则