Unity-UGUI无限循环列表

2019-07-25  本文已影响0人  祝你万事顺利

Unity版本:2017.4

简介:
UGUI使用ScrollView、GridLayoutGroup实现无限循环列表,支持数据刷新,支持跳转,支持动态插入/删除

实现思路:
基于Lua、UGUI(ScrollRect)实现
1.将全部样式存入一个Table
2.计算根据全部数据出整个Content的高度
3.根据当前Content的位置(anchoredPosition),计算出在显示区域内的子物体的索引
4.根据前面计算的可显示子物体索引,读取数据将相关数据进行显示
5.添加、删除、目标位置数据的跳转

Lua实现代码:
1.初始化样式

function InfiniteScrollRect:InitPreStyle()
    for i = 1, self.srContent:GetComponent(UnityEngine.RectTransform).childCount do
        local contentChild = self.srContent:GetComponent(UnityEngine.RectTransform):GetChild(i - 1)
        table.insert(
            self.preStyleTab,
            {
                content = contentChild,
                height = contentChild.sizeDelta.y
            }
        )
        table.insert(self.cachePool, {})
        table.insert(self.cachePool[i], contentChild)
    end
end

2.读取数据计算整个Content高度

function InfiniteScrollRect:CalculateHeight()
    local contentHeight = 0

    for dataIndex, dataItem in ipairs(self.dataTable) do
        local height = self.preStyleTab[dataItem.style].height
        contentHeight = contentHeight + height
    end

    self.srContent.sizeDelta = UnityEngine.Vector2(self.srContent.sizeDelta.x, contentHeight)
end

3.根据当前content的anchoredPosition计算可见

function InfiniteScrollRect:CalculateAreaIndexAndPadY(  )

    local height, padY = 0, 0
    local viewAreaTopDataIndex, viewAreaBottomDataIndex = -1, -1
    local contentPosY = self.srContent:GetComponent(UnityEngine.RectTransform).anchoredPosition.y
    local scrollingScrollRectHeight = self.scrollingScrollRect:GetComponent(UnityEngine.RectTransform).sizeDelta.y
    
    for dataIndex, dataItem in ipairs(self.dataTable) do
        local tempH = height
        height = height + self.preStyleTab[dataItem.style].height
        if viewAreaTopDataIndex == -1 and height > contentPosY then
            viewAreaTopDataIndex = dataIndex
            padY = tempH
        end
        if viewAreaBottomDataIndex == -1 and (dataIndex == #self.dataTable or ((contentPosY + scrollingScrollRectHeight) < height)) then
            viewAreaBottomDataIndex = dataIndex
            break
        end
    end
    return viewAreaTopDataIndex, viewAreaBottomDataIndex, padY
end

4.根据当前可见区域进行显示样式对应的GameObject,使用缓存池,如果缓存池轴中有可用的样式,将直接使用可用样式,缓存池中没有可用样式,实例化一个样式,并将其放入激活列表中

function InfiniteScrollRect:InstantiateScrollRectItems(topIndex, botIndex)

    self:clearActivatingPool()

    for i = topIndex, botIndex do
        local curStyle = self.dataTable[i].style
        local contentItem = nil
        if #self.cachePool[curStyle] > 0 then
            local item = table.remove(self.cachePool[curStyle])
            item.gameObject:SetActive(true)
            item:SetAsLastSibling()
            contentItem = item
        else
            local opLuaFile = OpenLuaFile.StaticIT()
            local instanceTr = opLuaFile:InstanceTransform(self.preStyleTab[curStyle].content, self.preStyleTab[curStyle].content.parent):GetComponent(UnityEngine.RectTransform)
            instanceTr:SetAsLastSibling()
            contentItem = instanceTr
        end
        table.insert(self.activatingPool, {content = contentItem, style = curStyle})
    end
end

5.遍历已经激活的列表,根据数据进行内容刷新

function InfiniteScrollRect:CalculateViewArea(forceFresh)
    local topIndex, botIndex, padY = self:CalculateAreaIndexAndPadY()
    local topDif, botDif = (self.lastTopIndex ~= topIndex),(self.lastBottomIndex ~= botIndex)

    if topDif or botDif or forceFresh then
        if topDif then
            local verticalLayoutGroup = self.srContent:GetComponent(UI.VerticalLayoutGroup)
            verticalLayoutGroup.padding.top = padY
        end
        self:InstantiateScrollRectItems(topIndex, botIndex)
        self:ShowItemDatas(topIndex, botIndex)
    end

    self.lastTopIndex = topIndex
    self.lastBottomIndex = botIndex
end
function InfiniteScrollRect:ShowItemDatas(topIndex, botIndex)
    for i, v in ipairs(self.activatingPool) do
        self.freshFunc(v.content, self.dataTable[topIndex + i - 1], topIndex + i - 1)
    end
end
上一篇下一篇

猜你喜欢

热点阅读