cocos2d-x lua 利用ScrollView实现虚拟列表

-- 创建虚拟列表类

local VirtualList = class("VirtualList")

---@param scrollView ccui.ScrollView

function VirtualList:ctor(scrollView,data,callback, offset)

    self.scrollView=scrollView

    -- self.scrollView:setClippingEnabled(false)

    local model =scrollView:getChildByName("model")

    model:setAnchorPoint(cc.p(0,1))

    self.itemPrefab =model

    model:retain()

    self.callback=callback

    self.offset=offset or 5

    self.itemContent={}

    self.scrollView:removeAllChildren()

    self.scrollViewSize =self.scrollView:getContentSize()

    self.item_h =self.itemPrefab:getContentSize().height

    self.item_w =self.itemPrefab:getContentSize().width

    self.onEvent=false

    self.selectUPId =0

    self.selectDownId=0

    self:initData(data)

    self:creatrViewMaxItems()

    self.lastPosition = cc.p(0, -self.content_h+self.scrollViewSize.height)

    self.scrollView:onNodeEvent("exit", function()

        self:disableNodeEvents()

    end)

    self.scrollView:setScrollBarEnabled(false)

end



function VirtualList:initData(data)

    self.data =data

    local col =self:getItemCols()

    local row =math.ceil(#self.data / col)

    local contentSize = cc.size(self.scrollViewSize.width, row*(self.item_h+self.offset))

    self.scrollView:setInnerContainerSize(contentSize)

    -- print("设置容易大小",contentSize.height,self.scrollView:getInnerContainerPosition().y)

    self.content_h=contentSize.height >=self.scrollViewSize.height and contentSize.height or self.scrollViewSize.height

    local maxRow =math.ceil(self.scrollViewSize.height/(self.item_h+self.offset))+1

    if maxRow*col<#self.data and not self.onEvent then

        self.onEvent=true

        self.scrollView:addEventListener(handler(self,self.onScrollViewEvent))

    end

end



--更新数据调用

function VirtualList:refreshUI(data,resetList)

    self.scrollView:stopAutoScroll()

    local old_len =#self.data

    local new_len = #data

    self.updateing =true

    local last_h =self.content_h

    local pos =self.scrollView:getInnerContainerPosition()

    self:initData(data)

    local now_h =self.content_h

    local change_h =now_h-last_h

    local cy =pos.y-change_h

    local type =0

    if old_len==new_len then

        type=0

        local maxRow =math.ceil(self.scrollViewSize.height/(self.item_h+self.offset))+1

        if old_len<maxRow*self:getItemCols() then

            self.selectUPId=0

            resetList=true

        end

        if resetList then

            self.selectUPId=0

            cy= -self.content_h+self.scrollViewSize.height

        end

        self.scrollView:setInnerContainerPosition(cc.p(0,cy))

    elseif old_len<new_len then

        --增加数据

        type =1

        local maxRow =math.ceil(self.scrollViewSize.height/(self.item_h+self.offset))+1

        if old_len<maxRow*self:getItemCols() then

            self.selectUPId=0

        end

        if resetList then

            self.selectUPId=0

            cy= -self.content_h+self.scrollViewSize.height

        end

        self.scrollView:setInnerContainerPosition(cc.p(0,cy))

    elseif old_len>new_len then

        --减少数据

        type =2

         self.selectUPId=0 --  减少必须从0开始

        self.scrollView:setInnerContainerPosition(cc.p(0,-self.content_h+self.scrollViewSize.height))

    end

    self:updateItem(change_h,type,resetList)

    self.updateing =false

end



--  计算行数

function VirtualList:getItemRows()

    local col =self:getItemCols()

    local row =0

    local maxRow =math.ceil(self.scrollViewSize.height/(self.item_h+self.offset))+1

    local minRow =math.ceil(#self.data / col)

    row =math.min(minRow,maxRow)

    return row

end



--  计算列数

function VirtualList:getItemCols()

    local size = self.scrollView:getInnerContainerSize()

    local col =math.floor(size.width/(self.item_w+self.offset))

    return col

end



--创建可视范围内的item数量

function VirtualList:creatrViewMaxItems()

    local index =1

    for i = 1,  self:getItemRows() do

        for j = 1, self:getItemCols() do

            local item = self.itemPrefab:clone()

            local h =self.content_h- (self.item_h+self.offset)*(i-1)

            item:setPosition(cc.p((j - 1) * (self.item_w+self.offset),h))

            self.scrollView:addChild(item)

            if not self.itemContent[i] then

                self.itemContent[i]={}

            end

            self.itemContent[i][j]=item

            if(index>#self.data) then

                item:setVisible(false)

                break

            end

            self:updateId(1)

            self.callback(item,self.data[self.selectUPId])

            index =index +1

        end

    end

end



--更新可视范围内的item

function VirtualList:updateItem(change_h,type,resetList)

    local row =self:getItemRows()

    local col =self:getItemCols()

    for i = 1,  row do

        for j = 1, col do

            local py =0

            local item

            if type == 1 then

                -- 增加数据

                if not self.itemContent[i] then

                    self.itemContent[i]={}

                    py=self.itemContent[i-1][1]:getPositionY()-(self.item_h+self.offset)

                else

                    if self.itemContent[i][j] then

                        py=self.itemContent[i][j]:getPositionY()+change_h

                    else

                        py=self.itemContent[i][1]:getPositionY()

                    end

                end

                item=self.itemContent[i][j]

                if not item then

                    item = self.itemPrefab:clone()

                    self.scrollView:addChild(item)

                    self.itemContent[i][j]=item

                    self:updateId(1)

                    if(self.selectUPId>#self.data) then

                        item:setVisible(false)

                    else

                        item:setVisible(true)

                        self.callback(item,self.data[self.selectUPId])

                    end

                else

                    local itemId

                    local maxRow =math.ceil(self.scrollViewSize.height/(self.item_h+self.offset))+1

                    if self.selectUPId>=maxRow*col  then

                        itemId =self.selectUPId-((row-(i-1))*col-j)

                    else

                        self:updateId(1)

                        itemId =self.selectUPId

                    end

                    if(itemId>#self.data) then

                        item:setVisible(false)

                    else

                        item:setVisible(true)

                        self.callback(item,self.data[itemId])

                    end

                end

                item:setPosition(cc.p((j - 1) * (self.item_w+self.offset),py))

            elseif type==2 then

                --减少数据

                item=self.itemContent[i][j]

                local h =self.content_h- (self.item_h+self.offset)*(i-1)

                item:setPosition(cc.p((j - 1) * (self.item_w+self.offset),h))

                if(self.selectUPId>#self.data) then

                    item:setVisible(false)

                else

                    item:setVisible(true)

                end

                self:updateId(1)

                self.callback(item,self.data[self.selectUPId])

            elseif type==0 then

                item=self.itemContent[i][j]

                local itemId

                if not resetList then

                    itemId =self.selectUPId-((row-(i-1))*col-j)

                else

                    self:updateId(1)

                    itemId =self.selectUPId

                    local h =self.content_h- (self.item_h+self.offset)*(i-1)

                    item:setPosition(cc.p((j - 1) * (self.item_w+self.offset),h))

                end

                if(itemId>#self.data) then

                    item:setVisible(false)

                else

                    item:setVisible(true)

                    self.callback(item,self.data[itemId])

                end

               

            end            

        end

    end    

end



function VirtualList:onScrollViewEvent(sender,eventType)

    if self.updateing then

        return

    end

    if eventType == ccui.ScrollviewEventType.containerMoved then

        -- ScrollView滚动中的逻辑处理

        local currentPosition = sender:getInnerContainerPosition()

        local delta = cc.p(currentPosition.x - self.lastPosition.x, currentPosition.y - self.lastPosition.y)

        self:updateItemPos(delta,math.floor(currentPosition.y-self.scrollViewSize.height))

        self.lastPosition =currentPosition

    end

end

-- type 1 up 2 down

function VirtualList:updateId(type)

    local row =self:getItemRows()

    local col =self:getItemCols()

    if type==1 then

        self.selectUPId =self.selectUPId+1

        local id=self.selectUPId-(row-1)*col-(col-1)

        self.selectDownId =id

        -- print("selectUPId 向上 =",self.selectUPId,self.selectDownId)

    else

        self.selectDownId =self.selectDownId-1

        local id=self.selectDownId + row*col-1

        self.selectUPId=id

       

        -- print("selectDownId 向下 =",self.selectDownId,self.selectUPId)

    end



end



--更新坐标

function VirtualList:updateItemPos(pos,offsetY)

   

    if pos.y==0 then

        return

    end

    if pos.y>0 then

        local item=self.itemContent[1][1]

        local startY =item:getPositionY()

        if -(startY-self.item_h-self.offset)<=offsetY then

            local firstElement = table.remove(self.itemContent, 1)

            local item =self.itemContent[#self.itemContent][1]

            local py1 =item:getPositionY()

            py1 =py1-(self.offset+self.item_h)

           

            -- print("移除头部并添加到末尾",self.selectUPId,py1)

            for index, value in ipairs(firstElement) do

                value:setPositionY(py1)

                self:updateId(1)

                if(self.selectUPId>#self.data) then

                    value:setVisible(false)

                else

                    value:setVisible(true)

                    self.callback(value,self.data[self.selectUPId])

                end



            end

            table.insert(self.itemContent, firstElement)

        end

    else

        local item=self.itemContent[#self.itemContent][1]

        local endY =item:getPositionY()+self.scrollViewSize.height

        if -(endY)>=offsetY then

            local lastElement = table.remove(self.itemContent)

            local py1 =self.itemContent[1][1]:getPositionY()

            py1 =py1+(self.offset+self.item_h)

            -- print("移除末尾并添加到头部",self.selectDownId,py1)

            for i = self:getItemCols(), 1,-1 do
                local item=lastElement[i]
                item:setPositionY(py1)
                item:setVisible(false)
                self:updateId(2)
                if self.selectDownId>=1 then
                    item:setVisible(true)
                    self.callback(item, self.data[self.selectDownId])
                end
            end
            table.insert(self.itemContent, 1, lastElement)
        end
    end

end



-- 退出界面时销毁监听器

function VirtualList:disableNodeEvents()



end



return VirtualList

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值