364 lines
No EOL
11 KiB
Lua
364 lines
No EOL
11 KiB
Lua
XScrollView = XClass(XLuaBehaviour, "XScrollView")
|
||
|
||
local DEFAULT_START_VALUE = 0.1 -- 默认起始坐标参数值
|
||
local DEFAULT_OFFSET_VALUE = 0.2 -- 默认间隔坐标参数值
|
||
local DEFAULT_MIN_VALUE = 0.1 -- 默认最小坐标参数值
|
||
local DEFAULT_MAX_VALUE = 0.9 -- 默认最大坐标参数值
|
||
|
||
local DEFAULT_ANIM_SPEED = 0.5 -- 默认动画速度
|
||
|
||
|
||
--==============================--
|
||
--desc: 构造函数
|
||
--@ui: 滑动展示区域Ui
|
||
--@scrollItems: 滑动列表
|
||
--@paramsObj: 扩展参数
|
||
--note: 可用扩展参数 selectIndex(默认显示第几条)、offsetValue(滑动列表间偏移量)、animSpeed(滑动速度)、
|
||
-- moveEndCb(滑动结束回掉)、direction(滑动方向,水平或者垂直)、isLoop(滑动列表是否循环)
|
||
--==============================--
|
||
function XScrollView:Ctor(rootUi, ui, scrollItems, paramsObj)
|
||
self.ScrollItems = {}
|
||
self.MoveEndCb = function() end
|
||
self.SelectItemCb = function() end
|
||
self.Direction = XScrollConfig.HORIZONTAL
|
||
|
||
self.Rect = self.Transform:GetComponent("RectTransform")
|
||
self.ContentSize = self.Rect.sizeDelta
|
||
|
||
self.StartValue = DEFAULT_START_VALUE
|
||
self.OffsetValue = DEFAULT_OFFSET_VALUE
|
||
self.MinValue = DEFAULT_MIN_VALUE
|
||
self.MaxValue = DEFAULT_MAX_VALUE
|
||
self.MinBorder = DEFAULT_MIN_VALUE
|
||
self.MaxBorder = DEFAULT_MAX_VALUE
|
||
self.AnimSpeed = DEFAULT_ANIM_SPEED
|
||
self.ItemsCount = #scrollItems
|
||
self.IsLoop = false
|
||
|
||
self.TotalOffset = 0 -- 重置总的滑动偏移计算
|
||
|
||
self:InitParams(paramsObj)
|
||
self:RegisterListener()
|
||
self:InitAnimationCurve()
|
||
self:InitScorllItems(scrollItems)
|
||
end
|
||
|
||
function XScrollView:AddSelectItemCallback(callback)
|
||
self.SelectItemCb = callback
|
||
end
|
||
|
||
function XScrollView:RemoveSelectItemCallback()
|
||
self.SelectItemCb = nil
|
||
end
|
||
|
||
function XScrollView:RegisterListener()
|
||
self.UiWidget = self.GameObject:AddComponent(typeof(CS.XUiWidget))
|
||
self.UiWidget:AddBeginDragListener(function(eventData)
|
||
self:OnBeginDrag(eventData)
|
||
end)
|
||
self.UiWidget:AddEndDragListener(function(eventData)
|
||
self:OnEndDrag(eventData)
|
||
end)
|
||
self.UiWidget:AddDragListener(function(eventData)
|
||
self:OnDrag(eventData)
|
||
end)
|
||
self.UiWidget:AddPointerClickListener(function(eventData)
|
||
self:OnPointerClick(eventData)
|
||
end)
|
||
end
|
||
|
||
function XScrollView:InitScorllItems(scrollItems)
|
||
local count = #scrollItems
|
||
|
||
for i = 1, count do
|
||
local item = scrollItems[i]
|
||
item:SetIndex(i)
|
||
item:SetParent(self)
|
||
item:OnDrag(self.StartValue + (i - 1) * self.OffsetValue)
|
||
if (not self.CurrentItem) and item.CurveValue - 0.5 < 0.05 then
|
||
self.CurrentItem = item
|
||
end
|
||
|
||
table.insert(self.ScrollItems, item)
|
||
end
|
||
|
||
local minCount = math.floor(1 / self.OffsetValue) -- 滑动区域可展示条目数
|
||
if #self.ScrollItems < minCount then
|
||
self.MaxValue = self.StartValue + (minCount - 1) * self.OffsetValue
|
||
else
|
||
self.MaxValue = self.StartValue + (count - 1) * self.OffsetValue
|
||
end
|
||
|
||
if self.SelectIndex then
|
||
self:SetSelectItem(self.SelectIndex)
|
||
end
|
||
end
|
||
|
||
function XScrollView:InitParams(paramsObj)
|
||
if not paramsObj or type(paramsObj) ~= "table" then
|
||
return
|
||
end
|
||
|
||
if paramsObj.selectIndex then
|
||
local selectIndex = paramsObj.selectIndex
|
||
if selectIndex < 1 or selectIndex > self.ItemsCount then
|
||
XLog.Warning("XScrollView InitParams use a Invalid selectIndex, selectIndex = " .. selectIndex)
|
||
else
|
||
self.SelectIndex = selectIndex
|
||
end
|
||
end
|
||
|
||
if paramsObj.offsetValue then
|
||
if paramsObj.offsetValue < 0 then
|
||
XLog.Warning("XScrollView InitParams use a Invalid offsetValue, offsetValue = " .. paramsObj.offsetValue)
|
||
else
|
||
self.OffsetValue = paramsObj.offsetValue
|
||
end
|
||
end
|
||
|
||
if paramsObj.animSpeed then
|
||
if paramsObj.animSpeed < 0 then
|
||
XLog.Warning("XScrollView InitParams use a Invalid animSpeed, animSpeed = " .. paramsObj.animSpeed)
|
||
else
|
||
self.AnimSpeed = paramsObj.animSpeed
|
||
end
|
||
end
|
||
|
||
if paramsObj.moveEndCb then
|
||
self.MoveEndCb = paramsObj.moveEndCb
|
||
end
|
||
|
||
if paramsObj.direction then
|
||
local direction = paramsObj.direction
|
||
if direction ~= XScrollConfig.HORIZONTAL and direction ~= XScrollConfig.VERTICAL then
|
||
XLog.Warning("XScrollView InitParams use a Invalid direction, direction = " .. direction)
|
||
else
|
||
self.Direction = direction
|
||
end
|
||
end
|
||
|
||
if paramsObj.isLoop ~= nil then
|
||
self.IsLoop = paramsObj.isLoop
|
||
end
|
||
end
|
||
|
||
function XScrollView:SetSelectItem(index)
|
||
self.CurrentItem = self.ScrollItems[index]
|
||
local offset = 0.5 - self.CurrentItem.CurveValue
|
||
for i = 1, #self.ScrollItems do
|
||
local item = self.ScrollItems[i]
|
||
item:OnDrag(offset)
|
||
end
|
||
|
||
self:AdjustScrollItems(offset)
|
||
if (self.SelectItemCb) then
|
||
self.SelectItemCb(self.CurrentItem)
|
||
end
|
||
end
|
||
|
||
function XScrollView:InitAnimationCurve()
|
||
-- Override this function
|
||
end
|
||
|
||
function XScrollView:OnBeginDrag(eventData)
|
||
self.StartPoint = eventData.position
|
||
self.AddVector = CS.UnityEngine.Vector3.zero
|
||
self.Anim = false
|
||
end
|
||
|
||
--==============================--
|
||
--desc: 滑动过程回掉
|
||
--@eventData: 回掉数据
|
||
--==============================--
|
||
function XScrollView:OnDrag()
|
||
-- Override this function
|
||
end
|
||
|
||
--==============================--
|
||
--desc: 滑动结束回掉滑动结束回掉
|
||
--@eventData: 回掉数据
|
||
--==============================--
|
||
function XScrollView:OnEndDrag()
|
||
-- Override this function
|
||
end
|
||
|
||
--==============================--
|
||
--desc: 动画曲线值计算接口
|
||
--@curveValue: 曲线值
|
||
--@return 动画计算产生的结果
|
||
--==============================--
|
||
function XScrollView:Evaluate(curveValue)
|
||
-- Override this function
|
||
end
|
||
|
||
--==============================--
|
||
--desc: 调整滑动列表元素
|
||
--@addValue: 增加的偏移量
|
||
--==============================--
|
||
function XScrollView:AdjustScrollItems(addValue)
|
||
if not self.IsLoop then
|
||
return
|
||
end
|
||
|
||
local itemCount = #self.ScrollItems
|
||
if addValue < 0 then -- left or down
|
||
local moveCount = 0
|
||
for i = 1, itemCount do
|
||
local item = self.ScrollItems[i]
|
||
if item.CurveValue < (self.MinValue - self.OffsetValue / 2) then
|
||
moveCount = moveCount + 1
|
||
end
|
||
end
|
||
|
||
if moveCount > 0 then
|
||
for _ = 1, moveCount do
|
||
local lastCurveValue = self.ScrollItems[itemCount].CurveValue
|
||
local item = table.remove(self.ScrollItems, 1)
|
||
item.CurveValue = lastCurveValue + self.OffsetValue
|
||
table.insert(self.ScrollItems, item)
|
||
end
|
||
end
|
||
elseif addValue > 0 then -- right or up
|
||
local moveCount = 0
|
||
for i = 1, itemCount do
|
||
local item = self.ScrollItems[i]
|
||
if item.CurveValue >= self.MaxValue then
|
||
moveCount = moveCount + 1
|
||
end
|
||
|
||
if moveCount > 0 then
|
||
local firstCurveValue = self.ScrollItems[1].CurveValue
|
||
local tmpItem = table.remove(self.ScrollItems, itemCount)
|
||
tmpItem.CurveValue = firstCurveValue - self.OffsetValue
|
||
table.insert(self.ScrollItems, 1, tmpItem)
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
--==============================--
|
||
--desc: 滑动结束动画处理
|
||
--@offset: 偏移量
|
||
--==============================--
|
||
function XScrollView:Anim2End(offset)
|
||
self.NeedOffset = offset -- 所需偏移量
|
||
if offset == 0 then
|
||
return
|
||
end
|
||
|
||
if offset > 0 then -- 正方向,向右/向上
|
||
self.MoveDir = 1
|
||
else -- 反方向,向左/向下
|
||
self.MoveDir = -1
|
||
end
|
||
|
||
self.Anim = true
|
||
self.TotalOffset = 0 -- 重置已偏移统计
|
||
end
|
||
|
||
--==============================--
|
||
--desc: 点击回掉,判断点中节点
|
||
--@eventData: 点击回掉数据
|
||
--==============================--
|
||
function XScrollView:OnPointerClick(eventData)
|
||
local gameObject = eventData.pointerPressRaycast.gameObject
|
||
for i = 1, #self.ScrollItems do
|
||
local item = self.ScrollItems[i]
|
||
if item.GameObject == gameObject then
|
||
if item.GameObject ~= self.CurrentItem.GameObject then
|
||
self.CurrentItem = item
|
||
self:Anim2End(0.5 - item.CurveValue)
|
||
end
|
||
break
|
||
end
|
||
end
|
||
end
|
||
|
||
function XScrollView:Update()
|
||
if not self.Anim then
|
||
return
|
||
end
|
||
|
||
local addOffset = CS.UnityEngine.Time.deltaTime * self.AnimSpeed * self.MoveDir
|
||
local totalOffset = self.TotalOffset + addOffset
|
||
|
||
if totalOffset > 0 and totalOffset >= self.NeedOffset then
|
||
self.Anim = false
|
||
addOffset = self.NeedOffset - self.TotalOffset
|
||
end
|
||
|
||
if totalOffset < 0 and totalOffset <= self.NeedOffset then
|
||
self.Anim = false
|
||
addOffset = self.NeedOffset - self.TotalOffset
|
||
end
|
||
|
||
for i = 1, #self.ScrollItems do
|
||
local item = self.ScrollItems[i]
|
||
item:OnDrag(addOffset)
|
||
if math.abs(item.CurveValue - 0.5) < 0.05 then -- 当前选中节点
|
||
self.CurrentItem = item
|
||
end
|
||
end
|
||
|
||
self:AdjustScrollItems(addOffset)
|
||
self.TotalOffset = totalOffset
|
||
|
||
if not self.Anim then
|
||
self.MoveEndCb(self.CurrentItem)
|
||
end
|
||
end
|
||
|
||
function XScrollView:LateUpdate()
|
||
local midItem
|
||
local minOffset = 1
|
||
for i = 1, #self.ScrollItems do
|
||
local item = self.ScrollItems[i]
|
||
local v = math.abs(item.CurveValue - 0.5)
|
||
-- if math.abs(item.CurveValue - 0.5) < 0.05 then -- 当前选中节点
|
||
-- midItem = item
|
||
-- end
|
||
if v < minOffset then
|
||
minOffset = v
|
||
midItem = item
|
||
end
|
||
|
||
end
|
||
|
||
if not midItem then
|
||
return
|
||
end
|
||
|
||
local midIndex = midItem.Index
|
||
local maxIndex = #self.ScrollItems
|
||
|
||
for i = 1, midIndex - 1 do
|
||
local item = self.ScrollItems[i]
|
||
-- if item.CurveValue >= self.MinBorder then
|
||
item.Rect:SetSiblingIndex(i)
|
||
-- else
|
||
-- break
|
||
-- end
|
||
end
|
||
|
||
for i = midIndex + 1, maxIndex do
|
||
local item = self.ScrollItems[i]
|
||
-- if item.CurveValue <= self.MaxBorder then
|
||
item.Rect:SetSiblingIndex(maxIndex - i)
|
||
-- else
|
||
-- break
|
||
-- end
|
||
end
|
||
|
||
midItem.Rect:SetSiblingIndex(maxIndex)
|
||
end
|
||
|
||
function XScrollView:Dispose()
|
||
local xLuaBehaviour = self.Transform:GetComponent("XLuaBehaviour")
|
||
if (xLuaBehaviour) then
|
||
CS.UnityEngine.GameObject.Destroy(xLuaBehaviour)
|
||
end
|
||
|
||
if (self.UiWidget) then
|
||
CS.UnityEngine.GameObject.Destroy(self.UiWidget)
|
||
end
|
||
end |