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

    【浮生梦】修复官方自适应代码

    [复制链接]

    321

    主题

    66

    回帖

    1445

    积分

    积分
    1445
    发表于 2025-4-24 02:36:15 | 显示全部楼层 |阅读模式
    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
    })
    

    0

    主题

    0

    回帖

    -20

    积分

    积分
    -20
    发表于 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
    复制代码

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

    本版积分规则