local scroll = {}
local MARGIN_UP
local MARGIN_LEFT
local MARGIN_V_BETWEEN
local MARGIN_H_BETWEEN
local NUM_PER_ROW
local THRESHOLD -- 与self['node' .. iHead]相对Container的高度差
local NODE_IHEAD_POS --inner的子节点位置
--[[
marginV: item间垂直间距,默认为 0
marginUp: 上下空白长度, 默认为 0
marginLeft: 左右空白长度,默认为 0
numPerRow: 每行item个数 ,默认为 1
]]
function setMargin(self, marginV, marginUp, marginLeft, numPerRow) --如果要设置则在create之前调用
MARGIN_V_BETWEEN = marginV or 0
MARGIN_UP = marginUp or 0
MARGIN_LEFT = marginLeft or 0
THRESHOLD = self.scv_height + (self.item_height + MARGIN_V_BETWEEN) / 2 + self.item_height
NUM_PER_ROW = numPerRow or 1
end
--[[
modName: 模块名
refScv: scroll view
refItem: item model
refData: 数据table, 用 #refData可获取长度
startRow: 希望从第几行开始显示, 默认为 1 ,程序会根据情况调整至合理位置
]]
function create(self, modName, refScv, refItem, refData, startRow)--一个页面可以重复调用
if self.iHead then
self:onExit() --主要为释放上一次的资源
end
self.modName = modName
self.scv = refScv
self.inner= self.scv:getInnerContainer()
self.item = refItem
self.item:setAnchorPoint(0, 0)
self.item:retain()
self.data = refData
self.item_width = self.item:getContentSize().width
self.item_height = self.item:getContentSize().height
self.scv_width = self.scv:getContentSize().width
self.scv_height = self.scv:getContentSize().height
self.iHead = startRow or 1
self:set_new_iHead_iTail() --首尾行需修正
self.pre_iHead = self.iHead
self:refresh('two_more_rows')
local function monitor()
self:monitor()
end
self.handle = cc.Director:getInstance():getScheduler():scheduleScriptFunc(monitor, 0, false)
end
local function monitor(self)
local innerY = self.inner:getPositionY()
if innerY + NODE_IHEAD_POS > THRESHOLD then --把头行移至尾后
if self.iTail == #self.data then
return
end
self['node' .. self.iHead + 1]:removeFromParent()
self['node' .. self.iHead + 1]:setPosition(0, NODE_IHEAD_POS)
self.inner:addChild(self['node' .. self.iHead + 1])
self['node' .. self.iHead]:removeFromParent()
self['node' .. self.iHead]:setPosition(0, -(self.item_height + MARGIN_V_BETWEEN))
self['node' .. self.iTail]:addChild(self['node' .. self.iHead])
self.inner:setPosition(0, innerY - (self.item_height + MARGIN_V_BETWEEN))
self['node' .. self.iTail + 1] = self['node' .. self.iHead]
self['node' .. self.iHead] = nil
for j = 1, NUM_PER_ROW do
local index1 = (self.iHead - 1) * NUM_PER_ROW + j
local index2 = (self.iTail + 1 - 1) * NUM_PER_ROW + j
self['item' .. index2] = self['item' .. index1]
self['item' .. index1] = nil
end
self.iHead = self.iHead + 1
self.iTail = self.iTail + 1
self:show_a_row(self.iTail)
else
if self.iHead == 1 then
return
end
self['node' .. self.iTail]:removeFromParent()
self['node' .. self.iTail]:setPosition(0, NODE_IHEAD_POS)
self.inner:addChild(self['node' .. self.iTail])
self['node' .. self.iHead]:removeFromParent()
self['node' .. self.iHead]:setPosition(0, -(self.item_height + MARGIN_V_BETWEEN))
self['node' .. self.iTail]:addChild(self['node' .. self.iHead])
self.inner:setPosition(0, innerY + (self.item_height + MARGIN_V_BETWEEN))
self['node' .. self.iHead - 1] = self['node' .. self.iTail]
self['node' .. self.iTail] = nil
for j = 1, NUM_PER_ROW do
local index1 = (self.iTail - 1) * NUM_PER_ROW + j
local index2 = (self.iHead - 1 - 1) * NUM_PER_ROW + j
self['item' .. index2] = self['item' .. index1]
self['item' .. index1] = nil
if not self['item' .. index2]:isVisible() then
self['item' .. index2]:setVisible(true)
end
end
self.iHead = self.iHead - 1
self.iTail = self.iTail - 1
self:show_a_row(self.iHead)
end
end
function jump_to(self, i) -- jump to i'th row
self.pre_iHead = self.iHead
self.iHead = i
self:refresh('two_more_rows')
end
function get_head_index(self) --返回self.iHead(首行标记)和innerContainer 的位置
return self.iHead
end
function get_inner_posY(self)
return self.inner:getPositionY()
end
function set_inner_posY(self, innerY)
self.inner:setPosition(0, innerY)
end
function onExit(self) --前端关闭页面前一定要调用,页面中不用手动调用
if self.handle then
cc.Director:getInstance():getScheduler():unscheduleScriptEntry(self.handle)
self.handle = nil
end
if self.item then
self.item:release()
self.item = nil
end
local j =self.iHead
if self['node' .. j] then
self['node' .. j]:removeFromParent()
end
while self['node' .. j] do --虽然上面已经释放,但是self内相关引用值不为nil,需赋为nil
self['node' .. j] = nil
for k = 1, NUM_PER_ROW do
local index = (j - 1) * NUM_PER_ROW + k
self['item' .. index] =nil
end
j = j + 1
end
self.iHead = nil
end
----------------------------------------------------------------------------
------------------------------以上函数外部可调用-----------------------------
----------------------------------------------------------------------------
local function show_a_row(self, i) -- i'th row
for j = 1, NUM_PER_ROW do
local index = (i - 1)*NUM_PER_ROW + j
if index > #self.data then
if not self['item' .. index] then
self['item' .. index] = self.item:clone()
self['item' .. index]:setPosition(MARGIN_LEFT + (self.item_width + MARGIN_H_BETWEEN) * (j - 1), -self.item_height)
self['node' .. i]:addChild(self['item' .. index])
self['item' .. index]:setVisible(false)
end
else
if not self['item' .. index] then
self['item' .. index] = self.item:clone()
self['item' .. index]:setPosition(MARGIN_LEFT + (self.item_width + MARGIN_H_BETWEEN) * (j - 1), -self.item_height)
self['node' .. i]:addChild(self['item' .. index])
else
if not self['item' .. index]:isVisible() then
self['item' .. index]:setVisible(true)
end
end
self:set_an_item(self['item' .. index], index)
end
end
end
local function set_an_item(self, item, i)
-- _G[self.modName].getInstance():set_an_item(item, i) --测试时注释掉
end
local function refresh(self , two_more_rows) --外界调用忽略第二个参数
local j = self.pre_iHead -- the previous index of head row
self:set_new_iHead_iTail()
local height = 2 * MARGIN_UP + (self.iTail - self.iHead + 1) * (self.item_height + MARGIN_V_BETWEEN) - MARGIN_V_BETWEEN --现在所需的inner高度
height = math.max(self.scv_height, height)
self.scv:setInnerContainerSize(cc.size(self.scv_width, height))
NODE_IHEAD_POS = height - MARGIN_UP -- 头节点的位置(相对于inner) ,其余node(i)的父节点是其上面的节点node(i - 1)
--复用之前可能存在的行,但之前的iHead ~ iTail 的行数或多或少或正好
local i = self.iHead -- the current index of head row
while i <= self.iTail do
if j == self.pre_iHead then
if not self['node' .. j] then
self['node' .. j] = cc.Node:create()
self.inner:addChild(self['node' .. j])
end
self['node' .. j]:setPosition(0, NODE_IHEAD_POS)
else
if not self['node' .. j] then
self['node' .. j]:setPosition(0, -(self.item_height + MARGIN_V_BETWEEN))
self['node' .. j - 1]:addChild(self['node' .. j])
end
end
self['node' .. i] = self['node' .. j] --需要注意前后node名可能相同
for k = 1, NUM_PER_ROW do
local index1 = (j - 1) * NUM_PER_ROW + k
local index2 = (i - 1) * NUM_PER_ROW + k
self['item' .. index2] = self['item' .. index1] --需要注意前后item名可能相同
if index2 ~= index1 then
self['item' .. index1] = nil
end
end
if i ~= j then
self['node' .. j] = nil --现在仅有 self['node' .. i]引用着 之前self['node' .. j]引用的 node
end
self:show_a_row(i)
i = i + 1
j = j + 1 --这里 j不用担心上界,如果item是nil则会在show_a_row里创建
end
if self['node' .. j] then --因为node(i)的父节点是node(i - 1),所以remove一个就行
self['node' .. j]:removeFromParent()
end
while self['node' .. j] do --虽然上面已经释放,但是self内相关引用值不为nil,需赋为nil
self['node' .. j] = nil
for k = 1, NUM_PER_ROW do
local index = (j - 1) * NUM_PER_ROW + k
self['item' .. index] =nil
end
j = j + 1
end
if two_more_rows then
self.count = 0
if self.count < 2 then
self:one_more_row_to_head()
end
if self.count < 2 then
self:one_more_row_to_tail()
end
if self.count < 2 then
self:one_more_row_to_head()
end
if self.count < 2 then
self:one_more_row_to_tail()
end
end
end
local function one_more_row_to_head(self)
if self.iHead == 1 then
return
end
self.count = self.count + 1
local height = self.inner:getContentSize().height
self.inner:setContentSize(cc.size(self.scv_width, height + (self.item_height + MARGIN_V_BETWEEN))) --这和setInnerContainerSize( 延伸方向不同
self['node' .. self.iHead - 1] = cc.Node:create()
NODE_IHEAD_POS = height - MARGIN_UP
self['node' .. self.iHead - 1]:setPosition(0, NODE_IHEAD_POS)
self.inner:addChild(self['node' .. self.iHead - 1])
self['node' .. self.iHead]:removeFromParent()
self['node' .. self.iHead]:setPosition(0, -(self.item_height + MARGIN_V_BETWEEN))
self['node' .. self.iHead - 1]:addChild(self['node' .. self.iHead])
self:show_a_row(self.iHead - 1)
self.iHead = self.iHead - 1
end
local function one_more_row_to_tail(self)
if self.iTail == #self.data then
return
end
self.count = self.count + 1
local height = self.inner:getContentSize().height
self.scv:setInnerContainerSize(cc.size(self.scv_width, height + (self.item_height + MARGIN_V_BETWEEN)))
self['node' .. self.iTail + 1] = cc.Node:create()
NODE_IHEAD_POS = height - MARGIN_UP
self['node' .. self.iTail + 1]:setPosition(0, -(self.item_height + MARGIN_V_BETWEEN))
self['node' .. self.iTail]:addChild(self['node' .. self.iTail])
self:show_a_row(self.iTail + 1)
self.iTail = self.iTail + 1
end
--当删除或添加items后应该调整之前的头尾位置
local function set_new_iHead_iTail(self )
local visible_rows = math.ceil(self.scv_height / (self.item_height + self.MARGIN_V_BETWEEN)) --可视域行数
local max_rows = math.ceil(#self.data / NUM_PER_ROW)
self.iTail = self.iHead + visible_rows - 1
self.iTail = math.min(max_rows, self.iTail)
self.iHead = self.iTail - visible_rows + 1
self.iHead = math.max(1, self.iHead)
--首先会显示可见区域items,然后最多添加 2 行,添加顺序 头 -> 尾 -> 头 -> 尾
end
_G['scroll'] = scroll
local MARGIN_UP
local MARGIN_LEFT
local MARGIN_V_BETWEEN
local MARGIN_H_BETWEEN
local NUM_PER_ROW
local THRESHOLD -- 与self['node' .. iHead]相对Container的高度差
local NODE_IHEAD_POS --inner的子节点位置
--[[
marginV: item间垂直间距,默认为 0
marginUp: 上下空白长度, 默认为 0
marginLeft: 左右空白长度,默认为 0
numPerRow: 每行item个数 ,默认为 1
]]
function setMargin(self, marginV, marginUp, marginLeft, numPerRow) --如果要设置则在create之前调用
MARGIN_V_BETWEEN = marginV or 0
MARGIN_UP = marginUp or 0
MARGIN_LEFT = marginLeft or 0
THRESHOLD = self.scv_height + (self.item_height + MARGIN_V_BETWEEN) / 2 + self.item_height
NUM_PER_ROW = numPerRow or 1
end
--[[
modName: 模块名
refScv: scroll view
refItem: item model
refData: 数据table, 用 #refData可获取长度
startRow: 希望从第几行开始显示, 默认为 1 ,程序会根据情况调整至合理位置
]]
function create(self, modName, refScv, refItem, refData, startRow)--一个页面可以重复调用
if self.iHead then
self:onExit() --主要为释放上一次的资源
end
self.modName = modName
self.scv = refScv
self.inner= self.scv:getInnerContainer()
self.item = refItem
self.item:setAnchorPoint(0, 0)
self.item:retain()
self.data = refData
self.item_width = self.item:getContentSize().width
self.item_height = self.item:getContentSize().height
self.scv_width = self.scv:getContentSize().width
self.scv_height = self.scv:getContentSize().height
self.iHead = startRow or 1
self:set_new_iHead_iTail() --首尾行需修正
self.pre_iHead = self.iHead
self:refresh('two_more_rows')
local function monitor()
self:monitor()
end
self.handle = cc.Director:getInstance():getScheduler():scheduleScriptFunc(monitor, 0, false)
end
local function monitor(self)
local innerY = self.inner:getPositionY()
if innerY + NODE_IHEAD_POS > THRESHOLD then --把头行移至尾后
if self.iTail == #self.data then
return
end
self['node' .. self.iHead + 1]:removeFromParent()
self['node' .. self.iHead + 1]:setPosition(0, NODE_IHEAD_POS)
self.inner:addChild(self['node' .. self.iHead + 1])
self['node' .. self.iHead]:removeFromParent()
self['node' .. self.iHead]:setPosition(0, -(self.item_height + MARGIN_V_BETWEEN))
self['node' .. self.iTail]:addChild(self['node' .. self.iHead])
self.inner:setPosition(0, innerY - (self.item_height + MARGIN_V_BETWEEN))
self['node' .. self.iTail + 1] = self['node' .. self.iHead]
self['node' .. self.iHead] = nil
for j = 1, NUM_PER_ROW do
local index1 = (self.iHead - 1) * NUM_PER_ROW + j
local index2 = (self.iTail + 1 - 1) * NUM_PER_ROW + j
self['item' .. index2] = self['item' .. index1]
self['item' .. index1] = nil
end
self.iHead = self.iHead + 1
self.iTail = self.iTail + 1
self:show_a_row(self.iTail)
else
if self.iHead == 1 then
return
end
self['node' .. self.iTail]:removeFromParent()
self['node' .. self.iTail]:setPosition(0, NODE_IHEAD_POS)
self.inner:addChild(self['node' .. self.iTail])
self['node' .. self.iHead]:removeFromParent()
self['node' .. self.iHead]:setPosition(0, -(self.item_height + MARGIN_V_BETWEEN))
self['node' .. self.iTail]:addChild(self['node' .. self.iHead])
self.inner:setPosition(0, innerY + (self.item_height + MARGIN_V_BETWEEN))
self['node' .. self.iHead - 1] = self['node' .. self.iTail]
self['node' .. self.iTail] = nil
for j = 1, NUM_PER_ROW do
local index1 = (self.iTail - 1) * NUM_PER_ROW + j
local index2 = (self.iHead - 1 - 1) * NUM_PER_ROW + j
self['item' .. index2] = self['item' .. index1]
self['item' .. index1] = nil
if not self['item' .. index2]:isVisible() then
self['item' .. index2]:setVisible(true)
end
end
self.iHead = self.iHead - 1
self.iTail = self.iTail - 1
self:show_a_row(self.iHead)
end
end
function jump_to(self, i) -- jump to i'th row
self.pre_iHead = self.iHead
self.iHead = i
self:refresh('two_more_rows')
end
function get_head_index(self) --返回self.iHead(首行标记)和innerContainer 的位置
return self.iHead
end
function get_inner_posY(self)
return self.inner:getPositionY()
end
function set_inner_posY(self, innerY)
self.inner:setPosition(0, innerY)
end
function onExit(self) --前端关闭页面前一定要调用,页面中不用手动调用
if self.handle then
cc.Director:getInstance():getScheduler():unscheduleScriptEntry(self.handle)
self.handle = nil
end
if self.item then
self.item:release()
self.item = nil
end
local j =self.iHead
if self['node' .. j] then
self['node' .. j]:removeFromParent()
end
while self['node' .. j] do --虽然上面已经释放,但是self内相关引用值不为nil,需赋为nil
self['node' .. j] = nil
for k = 1, NUM_PER_ROW do
local index = (j - 1) * NUM_PER_ROW + k
self['item' .. index] =nil
end
j = j + 1
end
self.iHead = nil
end
----------------------------------------------------------------------------
------------------------------以上函数外部可调用-----------------------------
----------------------------------------------------------------------------
local function show_a_row(self, i) -- i'th row
for j = 1, NUM_PER_ROW do
local index = (i - 1)*NUM_PER_ROW + j
if index > #self.data then
if not self['item' .. index] then
self['item' .. index] = self.item:clone()
self['item' .. index]:setPosition(MARGIN_LEFT + (self.item_width + MARGIN_H_BETWEEN) * (j - 1), -self.item_height)
self['node' .. i]:addChild(self['item' .. index])
self['item' .. index]:setVisible(false)
end
else
if not self['item' .. index] then
self['item' .. index] = self.item:clone()
self['item' .. index]:setPosition(MARGIN_LEFT + (self.item_width + MARGIN_H_BETWEEN) * (j - 1), -self.item_height)
self['node' .. i]:addChild(self['item' .. index])
else
if not self['item' .. index]:isVisible() then
self['item' .. index]:setVisible(true)
end
end
self:set_an_item(self['item' .. index], index)
end
end
end
local function set_an_item(self, item, i)
-- _G[self.modName].getInstance():set_an_item(item, i) --测试时注释掉
end
local function refresh(self , two_more_rows) --外界调用忽略第二个参数
local j = self.pre_iHead -- the previous index of head row
self:set_new_iHead_iTail()
local height = 2 * MARGIN_UP + (self.iTail - self.iHead + 1) * (self.item_height + MARGIN_V_BETWEEN) - MARGIN_V_BETWEEN --现在所需的inner高度
height = math.max(self.scv_height, height)
self.scv:setInnerContainerSize(cc.size(self.scv_width, height))
NODE_IHEAD_POS = height - MARGIN_UP -- 头节点的位置(相对于inner) ,其余node(i)的父节点是其上面的节点node(i - 1)
--复用之前可能存在的行,但之前的iHead ~ iTail 的行数或多或少或正好
local i = self.iHead -- the current index of head row
while i <= self.iTail do
if j == self.pre_iHead then
if not self['node' .. j] then
self['node' .. j] = cc.Node:create()
self.inner:addChild(self['node' .. j])
end
self['node' .. j]:setPosition(0, NODE_IHEAD_POS)
else
if not self['node' .. j] then
self['node' .. j]:setPosition(0, -(self.item_height + MARGIN_V_BETWEEN))
self['node' .. j - 1]:addChild(self['node' .. j])
end
end
self['node' .. i] = self['node' .. j] --需要注意前后node名可能相同
for k = 1, NUM_PER_ROW do
local index1 = (j - 1) * NUM_PER_ROW + k
local index2 = (i - 1) * NUM_PER_ROW + k
self['item' .. index2] = self['item' .. index1] --需要注意前后item名可能相同
if index2 ~= index1 then
self['item' .. index1] = nil
end
end
if i ~= j then
self['node' .. j] = nil --现在仅有 self['node' .. i]引用着 之前self['node' .. j]引用的 node
end
self:show_a_row(i)
i = i + 1
j = j + 1 --这里 j不用担心上界,如果item是nil则会在show_a_row里创建
end
if self['node' .. j] then --因为node(i)的父节点是node(i - 1),所以remove一个就行
self['node' .. j]:removeFromParent()
end
while self['node' .. j] do --虽然上面已经释放,但是self内相关引用值不为nil,需赋为nil
self['node' .. j] = nil
for k = 1, NUM_PER_ROW do
local index = (j - 1) * NUM_PER_ROW + k
self['item' .. index] =nil
end
j = j + 1
end
if two_more_rows then
self.count = 0
if self.count < 2 then
self:one_more_row_to_head()
end
if self.count < 2 then
self:one_more_row_to_tail()
end
if self.count < 2 then
self:one_more_row_to_head()
end
if self.count < 2 then
self:one_more_row_to_tail()
end
end
end
local function one_more_row_to_head(self)
if self.iHead == 1 then
return
end
self.count = self.count + 1
local height = self.inner:getContentSize().height
self.inner:setContentSize(cc.size(self.scv_width, height + (self.item_height + MARGIN_V_BETWEEN))) --这和setInnerContainerSize( 延伸方向不同
self['node' .. self.iHead - 1] = cc.Node:create()
NODE_IHEAD_POS = height - MARGIN_UP
self['node' .. self.iHead - 1]:setPosition(0, NODE_IHEAD_POS)
self.inner:addChild(self['node' .. self.iHead - 1])
self['node' .. self.iHead]:removeFromParent()
self['node' .. self.iHead]:setPosition(0, -(self.item_height + MARGIN_V_BETWEEN))
self['node' .. self.iHead - 1]:addChild(self['node' .. self.iHead])
self:show_a_row(self.iHead - 1)
self.iHead = self.iHead - 1
end
local function one_more_row_to_tail(self)
if self.iTail == #self.data then
return
end
self.count = self.count + 1
local height = self.inner:getContentSize().height
self.scv:setInnerContainerSize(cc.size(self.scv_width, height + (self.item_height + MARGIN_V_BETWEEN)))
self['node' .. self.iTail + 1] = cc.Node:create()
NODE_IHEAD_POS = height - MARGIN_UP
self['node' .. self.iTail + 1]:setPosition(0, -(self.item_height + MARGIN_V_BETWEEN))
self['node' .. self.iTail]:addChild(self['node' .. self.iTail])
self:show_a_row(self.iTail + 1)
self.iTail = self.iTail + 1
end
--当删除或添加items后应该调整之前的头尾位置
local function set_new_iHead_iTail(self )
local visible_rows = math.ceil(self.scv_height / (self.item_height + self.MARGIN_V_BETWEEN)) --可视域行数
local max_rows = math.ceil(#self.data / NUM_PER_ROW)
self.iTail = self.iHead + visible_rows - 1
self.iTail = math.min(max_rows, self.iTail)
self.iHead = self.iTail - visible_rows + 1
self.iHead = math.max(1, self.iHead)
--首先会显示可见区域items,然后最多添加 2 行,添加顺序 头 -> 尾 -> 头 -> 尾
end
_G['scroll'] = scroll