lua用cc.ScrollView自己实现TableView,并分页请求网络,刷新界面

本文介绍了一种自定义的列表视图实现方法,详细解释了如何通过Lua脚本语言和Cocos Creator游戏引擎构建垂直滑动的列表视图。包括了列表视图的初始化、数据重置、项数据更新、滑动重置、手动刷新项等功能。
摘要由CSDN通过智能技术生成

先上代码


local CustomListView = class("CustomListView", cc.Node);

--==============================--
--author:{SYL}
--desc: 列表 目前就实现垂直滑动的
--time:2019-03-13 08:47:57
--@_scrollView:  studio中拼的scrollView
--@_itemTemplate: 每一项的模版
--@_itemData:  总数据 格式是数组
--@_gridNum:  一行的数量
--@_spacingX: x间隔 目前没用是自动算的
--@_spacingY: y间隔
--@return 
--==============================--
function CustomListView:ctor(_scrollView,_itemTemplate,_itemData,_gridNum,_spacingX,_spacingY)    
    self._scrollView = _scrollView;
    self._itemTemplate = _itemTemplate;
    self._itemData = _itemData;
    self._gridNum = _gridNum or 1;
    self._spacingX = _spacingX or 0;
    self._spacingY = _spacingY or 0;

    self._spawnCount = _spawnCount;
    self._totalCount = _totalCount;
    self._bufferZone = _bufferZone;

    --逻辑参数,一般在外面要用到的一些值都放再这里,项中也可以取到
    self.logicParams = {};

    self:onUpdate(function(dt)
        self:updateAllItem(dt);
    end) 
    self:initialize();
end

--==============================--
--author:{SYL}
--desc:清空数据 初始化
--time:2019-03-15 04:15:20
--@logicParams:因为逻辑数据也会清空 需要重新传入
--@return 
--==============================--
function CustomListView:reset(logicParams)
    self:stopScroll();
    self:setTouchEnabled(false);
    self._itemData = {};
    self.logicParams = {};
    for k,v in pairs(logicParams) do
        self.logicParams[k] = v;
    end
    self:initialize();
    self:setTouchEnabled(true);
end

--==============================--
--author:{SYL}
--desc: 获取真实item的个数  计算获得 如果有需要可以继承重写此方法
--time:2019-03-15 04:16:12
--@return 
--==============================--
function CustomListView:getSpawnCount()
    local long = self._svContentSize.height;
    local longItem = self._itemContentSize.height;
    local num = math.floor(2*long/(longItem+self._spacingY));
    return num*self._gridNum;
end

--==============================--
--author:{SYL}
--desc: 滑动重置项的长度,有特殊需要可以继承重写此方法
--time:2019-03-15 04:16:56
--@return 
--==============================--
function CustomListView:getBufferZone()
    local long = self._svContentSize.height;
    return long;
end

--==============================--
--author:{SYL}
--desc: 重置项的数据 目前支持原来数据为0或者是一页 或者大于self:getSpawnCount() 
--当原数据个数大于一页小于self:getSpawnCount()时 重置的时候会把页面刷到顶上,之后有需求可以再完善
--传入的itemData比原来的大
--time:2019-03-15 04:17:43
--@_itemData: 传入的全部数据
--@return 
--==============================--
function CustomListView:reloadItemData(_itemData)    
    if #self._itemData<self:getSpawnCount() then
        self._itemData = _itemData;
        self:initialize();
    else
        self._itemData = _itemData;
        self:refreshItems();
    end
end

--==============================--
--author:{SYL}
--desc: 初始化项,清空列表中的节点,根据数据重新生成节点,一般外部不需要调用
--time:2019-03-15 04:29:16
--@return 
--==============================--
function CustomListView:initialize()
    self._content = self._scrollView:getInnerContainer();    
    self._svContentSize = self._scrollView:getContentSize();
    local tempItem = self._itemTemplate:create();
    self._itemContentSize = tempItem:getContentSize();
    self._spawnCount = self:getSpawnCount();
    self._bufferZone = self:getBufferZone();
    self._content:removeAllChildren();
    self._items = {};
    self._updateTimer = 0;
    self._updateInterval = 0;
    self._lastContentPosY = 0;
    self._totalCount = #self._itemData;
    self._spawnCount = self._totalCount>self._spawnCount and self._spawnCount or self._totalCount;
    self._contentSize = self._content:getContentSize();
    local height = math.ceil(self._totalCount/self._gridNum) * (self._itemContentSize.height + self._spacingY) + self._spacingY;
    height = height < self._svContentSize.height and self._svContentSize.height or height;
    self._scrollView:setInnerContainerSize(cc.size(self._contentSize.width,height));
    self._contentSize = self._content:getContentSize();
    --self:scrollToBegin()

    local gridNum = self._gridNum;
    for i=1,self._spawnCount do
        local item = self._itemTemplate:create();
        self._content:addChild(item);
        local hindex = math.floor((i-1)/gridNum);
        local gridIndex = (i-1)%gridNum;
        local dx = self._contentSize.width/gridNum;
        local x = dx/2+gridIndex*dx;
        local y = -self._itemContentSize.height * (0.5 + hindex) - self._spacingY * (hindex + 1);
        item:setPosition(cc.p(x, y+self._contentSize.height));
        item.itemID = i;
        item.logicParams = self.logicParams;
        self:updateItem(item);
        self._items[i] = item;
    end
end

--==============================--
--author:{SYL}
--desc:获取项相对于scrollView中心的坐标,一般外部不需要调用
--time:2019-03-15 04:30:21
--@item:项
--@return 
--==============================--
function CustomListView:getPositionInView(item)
    local worldPos = item:getParent():convertToWorldSpace(cc.p(item:getPosition()));
    local viewPos = self._scrollView:convertToNodeSpace(worldPos);
    --转换成scrollView锚点在0.5,0.5的坐标
    viewPos.y = viewPos.y-0.5*self._svContentSize.height;
    viewPos.x = viewPos.x+0.5*self._svContentSize.width;
    return viewPos;
end
--==============================--
--author:{SYL}
--desc: 更新项,封装一层便于继承修改
--time:2019-03-14 01:54:02
--@item: 需要更新的项
--@return 
--==============================--
function CustomListView:updateItem(item,bManual)
    item:updateItem(self._itemData[item.itemID],item.itemID,self._itemData,bManual);
    item:setVisible(self._itemData[item.itemID] and true or false);
end

--==============================--
--author:{SYL}
--desc:手动刷新每一项,根据需求调用,一般滑动的时候会自动刷新
--time:2019-03-15 04:31:38
--@return 
--==============================--
function CustomListView:refreshItems()
    local items = self._items;
    for i,v in ipairs(items) do
        self:updateItem(v,true);
    end
end

--==============================--
--author:{SYL}
--desc:更新项的方法 在发生滑动的时候判断然后更新要更新的项,内部调用,可以设置判断时间,目前是每帧都判断
--time:2019-03-15 04:32:20
--@dt:
--@return 
--==============================--
function CustomListView:updateAllItem(dt)
    if not self._items then
        return;
    end
    self._updateTimer = self._updateTimer+dt;
    if self._updateTimer < self._updateInterval then
        return;
    end
    self._updateTimer = 0;
    local items = self._items;
    local buffer = self._bufferZone;
    -- 如果当前content的y坐标小于上次记录值,则代表往下滚动,否则往上。
    local isDown = self._content:getPositionY() < self._lastContentPosY; --scrolling direction;
    local isUp = self._content:getPositionY() > self._lastContentPosY;
    -- 实际创建项占了多高(即它们的高度累加)
    local offset = (self._itemContentSize.height+self._spacingY)*math.ceil(#items/self._gridNum);
    --遍历数组,更新item的位置和显示
    for i=1,#items do
        local item = items[i];
        local viewPos = self:getPositionInView(item);
        if isDown then
            --如果往下滚动时item已经超出缓冲矩形,且items[i].y + offset未超出content上边界,
            --则更新item的坐标(即上移了一个offset的位置),同时更新item的显示内容
            local py = item:getPositionY();
            py = py-self._contentSize.height;
            if viewPos.y < -buffer and py + offset < 0 then
                item:setPositionY(item:getPositionY()+offset);
                local itemId = item.itemID - #items; --update item id  
                item.itemID = itemId;
                self:updateItem(item);                                                    
            end
        elseif isUp then
            --如果往上滚动时item已经超出缓冲矩形,且newY未超出content下边界,
            --则更新item的坐标(即下移了一个offset的位置),同时更新item的显示内容
            local py = item:getPositionY()
            py = py-self._contentSize.height
            if viewPos.y > buffer and py - offset > -self._contentSize.height then
                item:setPositionY(item:getPositionY()-offset)
                local itemId = item.itemID + #items; --update item id      
                item.itemID = itemId;
                self:updateItem(item);                                 
            end
        end
    end
    --update lastContentPosY
    self._lastContentPosY = self._content:getPositionY();

    --自动可以点击滑动
    if not self:isTouchEnabled() then
        if self._autoTouchEnabledTime then
            self._autoTouchEnabledTimeCount = self._autoTouchEnabledTime and self._autoTouchEnabledTime+dt or dt
            if self._autoTouchEnabledTimeCount>self.self._autoTouchEnabledTime then
                self._autoTouchEnabledTimeCount = self._autoTouchEnabledTimeCount - self.self._autoTouchEnabledTime;
                self:setTouchEnabled(true);
            end
        end
    end
end

--==============================--
--author:{SYL}
--desc:添加一项,想实现无感的往后面加一项,不会造成滑动,目前因为原来的scrollview只要改变了里面节点的size就会滑动所以没有实现,后面按需求完善
--time:2019-03-15 04:34:53
--@return 
--==============================--
function CustomListView:addItem()
    --self._totalCount = self._totalCount + 1;
    --local height = math.ceil(self._totalCount/self._gridNum) * (self._itemContentSize.height + self._spacingY) + self._spacingY;
    --self._scrollView:setInnerContainerSize(cc.size(self._contentSize.width,height));
end

--==============================--
--author:{SYL}
--desc: 滑到顶部,跳到顶部,滑到指定位置等方法后续再实现
--time:2019-03-13 08:56:50
--@stime: 活动时间
--@attenuated: 速度减弱true false
--@return 
--==============================--
function CustomListView:scrollToBegin(stime,attenuated)
    --self._scrollView:scrollToPercentVertical(0,stime or 0,attenuated);
end

--==============================--
--author:{SYL}
--desc:停止滑动
--time:2019-03-15 04:38:59
--@return 
--==============================--
function CustomListView:stopScroll()
    self._scrollView:stopAutoScroll();
    self._scrollView:stopScroll();
end

--==============================--
--author:{SYL}
--desc:设置点击状态,false就点不了,也就不能滑动了
--time:2019-03-15 04:39:10
--@b:
--@return 
--==============================--
function CustomListView:setTouchEnabled(b)
    self._scrollView:setTouchEnabled(b);
    self._autoTouchEnabledTime = nil;
end
--==============================--
--author:{SYL}
--desc:是否可点击/可滑动
--time:2019-03-15 04:39:39
--@return 
--==============================--
function CustomListView:isTouchEnabled()
    return self._scrollView:isTouchEnabled();
end

--==============================--
--author:{SYL}
--desc:设置不可滑动后,可以调这个方法,传入时间,一定时间后自动可以滑动
--time:2019-03-15 04:40:15
--@autoTime: 时间S
--@return 
--==============================--
function CustomListView:setAutoTouchEnabled(autoTime)
    self._autoTouchEnabledTime = autoTime;
end

return CustomListView


---------------------------------------------------------------------------------------

local CustomListViewItem = class("CustomListViewItem", ccui.Widget);
--==============================--
--author:{SYL}
--desc: 自定义列表组件的项 一般继承使用
--time:2019-03-15 04:41:53
--@csbFile:
--@return 
--==============================--
function CustomListViewItem:ctor(csbFile)
    if not csbFile then
        return;
    end
    self._ui = helper.loadUIQuick(self, csbFile,false,true);
    self:setContentSize(self._lytUi:getContentSize());
    self._ui:setPosition(cc.p(self._lytUi:getContentSize().width/2,self._lytUi:getContentSize().height/2));
    self._lytUi:setSwallowTouches(false);
end

function CustomListViewItem:onItemTouch(sender,event)
    if 0 == event then
        local worldPos = sender:getParent():convertToWorldSpace(cc.p(sender:getPosition()));
        self._touchBeganPos = worldPos;
    elseif 2 == event then
        local worldPos = sender:getParent():convertToWorldSpace(cc.p(sender:getPosition()));
        if math.abs(worldPos.y-self._touchBeganPos.y)>5 or math.abs(worldPos.x-self._touchBeganPos.x)>5 then
        else
            self:onItemClick();
        end        
    end
end

function CustomListViewItem:onItemClick()
    print(self.itemID);
end

function CustomListViewItem:updateItem(data,itemID,itemData)
    helper.setString(self._lyText, itemData);
end

return CustomListViewItem

 

网络请求方面,先定义好每页的数据,比如10条,第一次向服务端请求第一页数据  page=1,服务端返回总的数据数和10条数据

如 {len=100,data={1,2,3,4,5,6,7,8,9,10}},我先请求了2页,itemData前10项是数据,后90项用false填充,滑动的时候,滑到数据为false,就根据数据id,如11计算math.ceil(21/10),确定应该要请求第三页数据了,更新22就不用重复请求了,这里要用一个已经请求的表来控制,如果请求失败还要重新请求等,如果滑快了,先请求了第十页数据,上滑再请求第五页数据等,只要服务端返回的len个数,和每次的page和data个数确定,就可以比较完美的实现数据分次加载的listview了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值