|
|
LoopScrowViewMgr = LoopScrowViewMgr or BaseClass()
|
|
|
|
local LoopScrowViewMgr = LoopScrowViewMgr
|
|
|
|
function LoopScrowViewMgr:__init()
|
|
self.item_width = 100 --item 宽度
|
|
self.item_height = 100 --item 高度
|
|
|
|
self.cull_content = true --是否隐藏 滑动列表之外的物体
|
|
|
|
self.min_index = 0
|
|
self.max_index = 0
|
|
|
|
self.onInitializeItem = nil --更新item的委托
|
|
|
|
self.max_per_line = 1 --每一行有多少列
|
|
|
|
self.mTrans = nil --当前挂载这个组件的物体
|
|
|
|
self.mPanel = nil -- scrowView 物体
|
|
|
|
self.mScroll = nil -- scrowView 组件
|
|
|
|
self.mHorizontal = false --是否是水平
|
|
|
|
self.force_reset = true --强制复位
|
|
|
|
self.item_list = {}
|
|
|
|
self.mCachedScrowView = false
|
|
|
|
self.mOriginalPosition = Vector3.zero
|
|
|
|
self.mNeedToWrap = false
|
|
|
|
self.mPanelDelta = Vector2.zero
|
|
|
|
self.show_count = 0
|
|
|
|
self.item_num = 0
|
|
|
|
self.offset = 0
|
|
|
|
self.start_pos = {x=0, y=0}
|
|
|
|
self.corners = {}
|
|
|
|
self.wrap_content_cb = false
|
|
end
|
|
|
|
function LoopScrowViewMgr:Init(mPanel,mTrans,max_per_line,item_width,item_height,onInitializeItem,offset, offset_y, start_pos, wrap_content_cb)
|
|
self.mPanel = mPanel
|
|
if self.mPanel.transform.pivot.x ~= 0.5 or self.mPanel.transform.pivot.y ~= 0.5 then
|
|
-- 不要搞事情,计算的时候锚点不对会有计算错误请在预制就设置好scrollView的锚点
|
|
-- self.mPanel.transform.pivot = Vector2(0.5,0.5)
|
|
local size = self.mPanel.rect.size
|
|
local mPanel_x = GetLocalPositionX(self.mPanel.transform)
|
|
local mPanel_y = GetLocalPositionY(self.mPanel.transform)
|
|
if self.mPanel.transform.pivot.x == 0 and self.mPanel.transform.pivot.y == 1 then
|
|
self.mPanel.transform.localPosition = Vector3(mPanel_x + size.x/2, mPanel_y - size.y/2, 0)
|
|
elseif self.mPanel.transform.pivot.x == 1 and self.mPanel.transform.pivot.y == 0 then
|
|
self.mPanel.transform.localPosition = Vector3(mPanel_x - size.x/2, mPanel_y + size.y/2, 0)
|
|
end
|
|
self.mPanel.transform.pivot = Vector2(0.5,0.5)
|
|
end
|
|
|
|
self.mTrans = mTrans
|
|
self.item_width = item_width
|
|
self.item_height = item_height
|
|
self.max_per_line = max_per_line or 1
|
|
self.onInitializeItem = onInitializeItem
|
|
self.offset = offset or 0
|
|
self.start_pos = start_pos or {x=0, y=0}
|
|
self.wrap_content_cb = wrap_content_cb or false
|
|
self:CachedScrowView()
|
|
end
|
|
|
|
function LoopScrowViewMgr:__delete()
|
|
if self.mScroll then
|
|
self.mScroll.onValueChanged:RemoveAllListeners()
|
|
end
|
|
|
|
self.item_list = {}
|
|
|
|
self.onInitializeItem = nil --更新item的委托
|
|
self.mTrans = nil --当前挂载这个组件的物体
|
|
self.mPanel = nil -- scrowView 物体
|
|
self.mScroll = nil -- scrowView 组件
|
|
end
|
|
|
|
function LoopScrowViewMgr:ClearItemList()
|
|
if self.item_list then
|
|
for i,v in ipairs(self.item_list) do
|
|
v:SetVisible(false, true)
|
|
end
|
|
self.max_index = 0
|
|
end
|
|
end
|
|
|
|
|
|
function LoopScrowViewMgr:SetContentSizeData()
|
|
|
|
if self.mHorizontal then
|
|
if self.mTrans then
|
|
self.mTrans.sizeDelta = Vector2(math.ceil(self.show_count/self.max_per_line) * self.item_width,self.max_per_line * self.item_height)
|
|
end
|
|
else
|
|
if self.mTrans then
|
|
self.mTrans.sizeDelta = Vector2(self.max_per_line * self.item_width,math.ceil(self.show_count/self.max_per_line) * self.item_height)
|
|
end
|
|
end
|
|
end
|
|
|
|
function LoopScrowViewMgr:CachedScrowView()
|
|
if self.mCachedScrowView then
|
|
if self.mScroll == nil then
|
|
return
|
|
end
|
|
return self.mScroll and self.mScroll.horizontal or self.mScroll.vertical
|
|
end
|
|
|
|
self.mCachedScrowView = true
|
|
|
|
if self.mPanel == nil then return false end
|
|
if self.mTrans == nil then return false end
|
|
|
|
self.mPanelDelta = self.mPanel.rect.size
|
|
|
|
self.mOriginalPosition = self.mTrans.localPosition
|
|
self.mScroll = self.mPanel.gameObject:GetComponent("ScrollRect")
|
|
|
|
if self.mScroll == nil then return false end
|
|
|
|
if self.mScroll.horizontal then
|
|
self.mHorizontal = true
|
|
elseif self.mScroll.vertical then
|
|
self.mHorizontal = false
|
|
else
|
|
return false
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
function LoopScrowViewMgr:InitChildren(item_list,show_count)
|
|
self.show_count = show_count
|
|
if not self:CachedScrowView() then
|
|
return
|
|
end
|
|
|
|
if item_list then
|
|
local len = TableSize(item_list)
|
|
self.min_index = 1
|
|
self.max_index = show_count
|
|
self.mNeedToWrap = show_count > len
|
|
self.item_list = {}
|
|
|
|
if show_count < 0 or show_count > len then
|
|
show_count = len
|
|
end
|
|
|
|
local item
|
|
for i = 1,len do
|
|
item = item_list[i]
|
|
if show_count > 0 and item then
|
|
item:SetVisible(true, true)
|
|
table.insert(self.item_list,item)
|
|
show_count = show_count - 1
|
|
elseif item then
|
|
table.insert(self.item_list,item)
|
|
item:SetVisible(false, true)
|
|
end
|
|
end
|
|
--是真实的item个数
|
|
self.item_num = #self.item_list
|
|
else
|
|
self.item_num = 0
|
|
end
|
|
end
|
|
|
|
function LoopScrowViewMgr:ResetScrowViewPanel(is_not_reset_pos)
|
|
local is_not_reset_pos = is_not_reset_pos
|
|
if self.mScroll then
|
|
self.mScroll.onValueChanged:RemoveAllListeners()
|
|
self:ResetPosition(is_not_reset_pos)
|
|
self.mScroll.onValueChanged:AddListener(function()
|
|
self:WrapContent()
|
|
end)
|
|
end
|
|
end
|
|
|
|
function LoopScrowViewMgr:ResetPosition(is_not_reset_pos)
|
|
if not is_not_reset_pos then
|
|
self.mTrans.localPosition = self.mOriginalPosition
|
|
end
|
|
end
|
|
|
|
function LoopScrowViewMgr:ResetItemListPosition()
|
|
local len = self.item_num
|
|
for i = 1,len do
|
|
local item = self.item_list[i]
|
|
-- item:SetGameObjectName(tostring(i))
|
|
|
|
if self.mHorizontal then
|
|
local pos = self.max_per_line > 0 and
|
|
Vector3(math.floor((i - 1) / self.max_per_line) * self.item_width + self.offset,- (math.floor(i - 1) % self.max_per_line * self.item_height), 0) or
|
|
Vector3(-(i-1) * self.item_width,0,0)
|
|
item:SetPosition(pos.x +self.start_pos.x, pos.y + self.start_pos.y)
|
|
else
|
|
local pos = self.max_per_line > 0 and
|
|
Vector3(math.floor(i - 1) % self.max_per_line * self.item_width ,- math.floor((i - 1) / self.max_per_line) * self.item_height,0) or
|
|
Vector3(0,-(i-1) * self.item_height,0)
|
|
item:SetPosition(pos.x +self.start_pos.x, pos.y + self.start_pos.y)
|
|
end
|
|
end
|
|
end
|
|
|
|
function LoopScrowViewMgr:RestToBeginning(is_not_reset_pos)--is_not_reset_pos为true则不重置scroll位置
|
|
|
|
if not self:CachedScrowView() then
|
|
return
|
|
end
|
|
|
|
self:ResetScrowViewPanel(is_not_reset_pos)
|
|
self:ResetItemListPosition()
|
|
self.force_reset = true
|
|
self:WrapContent()
|
|
self.force_reset = false
|
|
end
|
|
|
|
--强制更新所有item数据
|
|
function LoopScrowViewMgr:ForceUpdateCurrentItems()
|
|
-- self.force_reset = true
|
|
-- self:WrapContent()
|
|
-- self.force_reset = false
|
|
if self.mNeedToWrap and self.mTrans then
|
|
self.corners = self:GetWorldCorners()
|
|
for i = 1,4 do
|
|
local v = self.corners[i]
|
|
v = self.mTrans:InverseTransformPoint(v)
|
|
self.corners[i] = v
|
|
end
|
|
end
|
|
self:ForceUpdatePos(self.corners)
|
|
end
|
|
|
|
function LoopScrowViewMgr:ForceUpdatePos(corners)
|
|
if corners == nil or #corners < 1 then return end
|
|
if self.mHorizontal then
|
|
local extents = self.max_per_line > 0 and (self.item_width * math.floor(self.item_num / self.max_per_line)) or self.item_width * self.item_num
|
|
local halfExtents = extents*0.5
|
|
local center = (corners[1] + corners[3]) * 0.5
|
|
for i = 1,self.item_num do
|
|
local item = self.item_list[i]
|
|
local distance = item:GetPosition().x + self.item_width/2 - center.x
|
|
local realIndex = self:GetRealIndex(item:GetPosition())
|
|
if self.min_index == self.max_index or (self.min_index <= realIndex and realIndex <= self.max_index) then
|
|
-- item:SetGameObjectName(tostring(realIndex))
|
|
if self.max_index > #self.item_list then
|
|
item:SetVisible(true, true)
|
|
end
|
|
self:UpdateItem(item,i,realIndex)
|
|
else
|
|
item:SetVisible(false, true)
|
|
end
|
|
if extents > self.mPanelDelta.x then
|
|
if math.abs(distance) > halfExtents then
|
|
local pos = DeepCopy(item:GetPosition())
|
|
pos.x = distance < 0 and pos.x + extents or pos.x - extents
|
|
local realIndex = self:GetRealIndex(pos)
|
|
if self.min_index == self.max_index or (self.min_index <= realIndex and realIndex <= self.max_index) then
|
|
item:SetPosition(pos.x, pos.y)
|
|
-- item:SetGameObjectName(tostring(realIndex))
|
|
if self.max_index > #self.item_list then
|
|
item:SetVisible(true, true)
|
|
end
|
|
self:UpdateItem(item,i,realIndex)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
else
|
|
local extents = self.max_per_line > 0 and (self.item_height * math.floor(self.item_num / self.max_per_line)) or self.item_height * self.item_num
|
|
local halfExtents = extents*0.5
|
|
local center = (corners[1] + corners[3]) * 0.5
|
|
for i = 1,self.item_num do
|
|
local item = self.item_list[i]
|
|
local distance = item:GetPosition().y - self.item_height/2 - center.y
|
|
local realIndex = self:GetRealIndex(item:GetPosition())
|
|
if self.min_index == self.max_index or (self.min_index <= realIndex and realIndex <= self.max_index) then
|
|
-- item:SetGameObjectName(tostring(realIndex))
|
|
if self.max_index > #self.item_list then
|
|
item:SetVisible(true, true)
|
|
end
|
|
self:UpdateItem(item,i,realIndex)
|
|
else
|
|
item:SetVisible(false, true)
|
|
end
|
|
if extents > self.mPanelDelta.y then
|
|
if math.abs(distance) > halfExtents then
|
|
local pos = DeepCopy(item:GetPosition())
|
|
pos.y = distance < 0 and pos.y + extents or pos.y - extents
|
|
local realIndex = self:GetRealIndex(pos)
|
|
if self.min_index == self.max_index or (self.min_index <= realIndex and realIndex <= self.max_index) then
|
|
item:SetPosition(pos.x, pos.y)
|
|
-- item:SetGameObjectName(tostring(realIndex))
|
|
if self.max_index > #self.item_list then
|
|
item:SetVisible(true, true)
|
|
end
|
|
self:UpdateItem(item,i,realIndex)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function LoopScrowViewMgr:GetWorldCorners()
|
|
|
|
local mCorners = {}
|
|
|
|
local x0 = -0.5 * self.mPanelDelta.x
|
|
local y0 = -0.5 * self.mPanelDelta.y
|
|
local x1 = x0 + self.mPanelDelta.x
|
|
local y1 = y0 + self.mPanelDelta.y
|
|
|
|
mCorners[1] = self.mPanel:TransformPoint(x0,y0,0)
|
|
mCorners[2] = self.mPanel:TransformPoint(x0,y1,0)
|
|
mCorners[3] = self.mPanel:TransformPoint(x1,y1,0)
|
|
mCorners[4] = self.mPanel:TransformPoint(x1,y0,0)
|
|
|
|
return mCorners
|
|
|
|
end
|
|
|
|
function LoopScrowViewMgr:WrapContent()
|
|
|
|
if not self:CachedScrowView() then
|
|
return
|
|
end
|
|
|
|
if self.mNeedToWrap or self.force_reset then
|
|
self.corners = self:GetWorldCorners()
|
|
for i = 1,4 do
|
|
local v = self.corners[i]
|
|
v = self.mTrans:InverseTransformPoint(v)
|
|
self.corners[i] = v
|
|
end
|
|
if self.mHorizontal then
|
|
self:WrapHorizontal(self.corners)
|
|
else
|
|
self:WrapVertical(self.corners)
|
|
end
|
|
end
|
|
|
|
if self.wrap_content_cb then
|
|
self.wrap_content_cb()
|
|
end
|
|
end
|
|
|
|
function LoopScrowViewMgr:GetRealIndex(pos)
|
|
if self.mHorizontal then
|
|
return self.max_per_line > 0 and
|
|
--这里一定要四舍五入,因为 位置会出现 原本 是 440,unity 可能会变成439.333
|
|
round((pos.x - self.offset) / self.item_width) * self.max_per_line + round(-pos.y / self.item_height) + 1 or
|
|
round(pos.x / self.item_width)
|
|
else
|
|
return self.max_per_line > 0 and
|
|
--这里一定要四舍五入,因为 位置会出现 原本 是 440,unity 可能会变成439.333
|
|
round(- pos.y / self.item_height) * self.max_per_line + round(pos.x / self.item_width) + 1 or
|
|
round(- pos.y / self.item_height)
|
|
end
|
|
end
|
|
|
|
function LoopScrowViewMgr:WrapVertical(corners)
|
|
local extents = self.max_per_line > 1 and (self.item_height * math.floor(self.item_num / self.max_per_line)) or self.item_height * self.item_num
|
|
|
|
local halfExtents = extents*0.5
|
|
local center = (corners[1] + corners[3]) * 0.5
|
|
for i = 1,self.item_num do
|
|
local item = self.item_list[i]
|
|
|
|
local distance = item:GetPosition().y - self.item_height/2 - center.y
|
|
if self.force_reset then
|
|
local realIndex = self:GetRealIndex(item:GetPosition())
|
|
if self.min_index == self.max_index or (self.min_index <= realIndex and realIndex <= self.max_index) then
|
|
-- item:SetGameObjectName(tostring(realIndex))
|
|
if self.max_index > #self.item_list then
|
|
item:SetVisible(true, true)
|
|
end
|
|
self:UpdateItem(item,i,realIndex)
|
|
end
|
|
elseif extents > self.mPanelDelta.y then
|
|
if math.abs(distance) > halfExtents then
|
|
local pos = DeepCopy(item:GetPosition())
|
|
pos.y = distance < 0 and pos.y + extents or pos.y - extents
|
|
local realIndex = self:GetRealIndex(pos)
|
|
if self.min_index == self.max_index or (self.min_index <= realIndex and realIndex <= self.max_index) then
|
|
item:SetPosition(pos.x, pos.y)
|
|
-- item:SetGameObjectName(tostring(realIndex))
|
|
if self.max_index > #self.item_list then
|
|
item:SetVisible(true, true)
|
|
end
|
|
self:UpdateItem(item,i,realIndex)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function LoopScrowViewMgr:WrapHorizontal(corners)
|
|
local extents = self.max_per_line > 0 and (self.item_width * math.floor(self.item_num / self.max_per_line)) or self.item_width * self.item_num
|
|
|
|
local halfExtents = extents*0.5
|
|
local center = (corners[1] + corners[3]) * 0.5
|
|
for i = 1,self.item_num do
|
|
local item = self.item_list[i]
|
|
|
|
local distance = item:GetPosition().x + self.item_width/2 - center.x
|
|
if self.force_reset then
|
|
local realIndex = self:GetRealIndex(item:GetPosition())
|
|
if self.min_index == self.max_index or (self.min_index <= realIndex and realIndex <= self.max_index) then
|
|
-- item:SetGameObjectName(tostring(realIndex))
|
|
if self.max_index > #self.item_list then
|
|
item:SetVisible(true, true)
|
|
end
|
|
self:UpdateItem(item,i,realIndex)
|
|
end
|
|
elseif extents > self.mPanelDelta.x then
|
|
if math.abs(distance) > halfExtents then
|
|
local pos = DeepCopy(item:GetPosition())
|
|
pos.x = distance < 0 and pos.x + extents or pos.x - extents
|
|
local realIndex = self:GetRealIndex(pos)
|
|
if self.min_index == self.max_index or (self.min_index <= realIndex and realIndex <= self.max_index) then
|
|
item:SetPosition(pos.x, pos.y)
|
|
-- item:SetGameObjectName(tostring(realIndex))
|
|
if self.max_index > #self.item_list then
|
|
item:SetVisible(true, true)
|
|
end
|
|
self:UpdateItem(item,i,realIndex)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function LoopScrowViewMgr:UpdateItem(item,index,realIndex)
|
|
if self.onInitializeItem then
|
|
self.onInitializeItem(item,index,realIndex)
|
|
end
|
|
end
|
|
|
|
function LoopScrowViewMgr:CenterOnChild(index)
|
|
local floor = math.floor
|
|
if self.mHorizontal then
|
|
local view_num = floor(self.mPanelDelta.x/self.item_width)
|
|
local endPoint = self.mTrans.sizeDelta.x - self.item_width
|
|
local offset = (index - math.ceil(view_num/2)) * self.item_width
|
|
for i = 1,self.item_num do
|
|
local item = self.item_list[i]
|
|
local pos = item:GetPosition()
|
|
pos.x = (i-1)*self.item_width + offset
|
|
pos.x = pos.x <= endPoint and pos.x or (offset - (i-1)*self.item_width)
|
|
item:SetPosition(pos.x, pos.y)
|
|
local realIndex = self:GetRealIndex(pos)
|
|
self:UpdateItem(item,i,realIndex)
|
|
end
|
|
local content_pos = self.mTrans.anchoredPosition
|
|
content_pos.x = content_pos.x - offset
|
|
self.mTrans.anchoredPosition = content_pos
|
|
else
|
|
|
|
end
|
|
|
|
end
|
|
|
|
--跳转到实际索引所在的位置
|
|
function LoopScrowViewMgr:JumpToChild(index)
|
|
if index and index > 0 then
|
|
print("==== jump to index:", index)
|
|
if self.mHorizontal then
|
|
if self.show_count * self.item_width > self.mPanel.sizeDelta.x then
|
|
local max_index = math.min(self.max_index, self.item_num)
|
|
local tran_posX = -(index - 1)*self.item_width
|
|
if tran_posX < -(self.show_count * self.item_width - self.mPanel.sizeDelta.x) then
|
|
tran_posX = -(self.show_count * self.item_width - self.mPanel.sizeDelta.x)
|
|
end
|
|
self.mTrans.localPosition = Vector2(tran_posX, self.mTrans.localPosition.y)
|
|
local op_index = 1
|
|
for i = 1, max_index do
|
|
local item = self.item_list[i]
|
|
local pos = item:GetPosition()
|
|
pos.x = (i + index - 2)*self.item_width - self.offset
|
|
if pos.x >= (self.show_count * self.item_width) then
|
|
op_index = op_index + 1
|
|
pos.x = -(op_index - index)*self.item_width - self.offset
|
|
end
|
|
item:SetPosition(pos.x + self.start_pos.x, pos.y + self.start_pos.y)
|
|
local realIndex = self:GetRealIndex(pos)
|
|
-- item:SetGameObjectName(tostring(realIndex))
|
|
self:UpdateItem(item,i,realIndex)
|
|
end
|
|
end
|
|
else
|
|
if self.show_count * self.item_height > self.mPanel.sizeDelta.y then
|
|
local max_index = math.min(self.max_index, self.item_num)
|
|
local tran_posY = (index - 1)*self.item_height
|
|
if tran_posY > (self.show_count * self.item_height - self.mPanel.sizeDelta.y) then
|
|
tran_posY = self.show_count * self.item_height - self.mPanel.sizeDelta.y
|
|
end
|
|
self.mTrans.localPosition = Vector2(self.mTrans.localPosition.x, tran_posY)
|
|
local op_index = 1
|
|
for i = 1, max_index do
|
|
local item = self.item_list[i]
|
|
local pos = item:GetPosition()
|
|
pos.y = -(math.ceil(i/self.max_per_line) + index - 2)*self.item_height
|
|
if pos.y <= -(self.show_count * self.item_height) then
|
|
op_index = op_index + 1
|
|
pos.y = (op_index - index)*self.item_height
|
|
end
|
|
item:SetPosition(pos.x + self.start_pos.x, pos.y + self.start_pos.y)
|
|
local realIndex = self:GetRealIndex(pos)
|
|
self:UpdateItem(item,i,realIndex)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--获取展示在显示窗口的item
|
|
function LoopScrowViewMgr:GetShowInViewportItem()
|
|
local mPos = self.mTrans.localPosition
|
|
local show_key_list = {}
|
|
for k,v in pairs(self.item_list) do
|
|
local bool_visible = v:GetVisible()
|
|
if bool_visible then
|
|
local pos = v:GetPosition()
|
|
if (mPos.y+pos.y) <= self.item_height/2 and (mPos.y+pos.y) >= -self.mPanelDelta.y
|
|
and (mPos.x+pos.x) >= -self.item_width/2 and (mPos.x+pos.x) <= self.mPanelDelta.x then
|
|
table.insert(show_key_list, k)
|
|
end
|
|
end
|
|
end
|
|
return show_key_list
|
|
end
|