双滑动列表实现
推荐阅读:
在项目中,我们经常会使用到列表来展示奖励或者任务,通常我们遇见的都是很简单的单滑动列表,如下案列:
这不,最近有个新功能,需要展示一个进度滑动列表和一个奖励滑动列表,如下案例
首先想到的是将进度条和奖励弄在一个item上面,但是现在问题来了,看看美术给的图
由于边角是圆角的,直接用的话会出现以下情况:
尝试一
为了方便,便考虑在不考虑修改美术资源的情况下,来实现功能。于是我才用了另一种方案:
考虑使用两个循环列表实现,为了不造成卡顿,减少内存消耗等,还是采用无限列表来实现:
新建两个ScrollView,分别为进度滑动列表和奖励滑动列表,命名为::left和right
滑动实现方法:一个无限列表位置改变带动另一个位置改变:
function base.updaterender(go, index)
local posRigth = ui.list.gameObject.transform.localPosition
local posLeft = ui.proglist.gameObject.transform.localPosition
ui.proglist.gameObject.transform.localPosition = Vector2.New(posLeft.x,posRigth.y)
end
运行效果发现:右侧无限列表带动左边滑动,左边的滑动列表会有明显的滞后感,而且最后停留的位置也会有很大的偏差,至此,此方法行不通,考虑下一种方法.
尝试二
新建一个ScrollView,该Content下面包含两个无限列表:left和right
运行发现没有问题,但是在自以为快要完成功能时发现了问题:当需要指定滑动到某个item时,会造成如下情况:
观察发现,ScrollView/Viewport/Content位置正确,rig话题,left位置正确,但是left和right里面的item位置回到了初始值(即:跑到了最顶端),造成这样的现象是无限列表代码里,每次刷新,会将item位置重置。为了不修改无限列表代码(因为项目很多地方在用,修改了其他地方可能会出现bug),考虑其他方式。在尝试了很多方式后未果,突发奇想,是否可以用一个动画来滑动到指定问题。于是尝试一番之后发现,完美!!!至此,此功能终于解决了~~
local function SliderIdx()
local idx = FindCanGetIdx()--需要滑动到的item下标
local pos = ui.content.transform.localPosition
local posY
if idx then
posY = (idx-1)*111.35
ui.content.gameObject.transform.localPosition = Vector2.New(0, 0)
ui.content.gameObject.transform:DOLocalMove(Vector2.New(0, posY), 0.8, false):SetEase(Ease.Linear):Play()
else
ui.content.transform.localPosition = Vector2.New(ui.content.transform.localPosition.x,0)
end
end
尝试三
问题解决了,可以考虑下修改美术资源,将进度和奖励整合在一个item上实现,打开在线ps,剪裁掉两边的圆角,成品如下:
这个方法ui表现没有问题,但是在进度计算又遇到问题了,开始的想法是每个进度=当前完成/当前需要,结果发现,在出现如下现象:
这种低级错误我就不多说了,在座各位都比我优秀。
然后判断当前完成与上一进度的大小;当前完成与下一进度的大小;当前完成与当前进度的大小,然后单独处理。这样发现,本来清晰的思路写着写着就混乱了,于是又才用另一种思路计算,首先计算当前点的上方进度,然后再计算下方进度:
--haveExp:当前拥有的
--ui.proto[index-1].exp:上一个item需要达到的
--ui.proto[index].exp:当前item需要达到的
--ui.proto[index+1].exp:下一个item需要达到的
--topSlider:上方进度
--botSlider:下方进度
-- 上面
local last = ui.proto[index-1] and ui.proto[index-1].exp or 0
if (haveExp - last) <= 0 then
topSlider.value = 0
elseif (haveExp - ui.proto[index].exp) >= 0 then
topSlider.value = 1
else
local total = (haveExp - last) / (ui.proto[index].exp - last)
topSlider.value = math.max(total-0.5,0)
end
--下面
if ui.proto[index+1] then
local _next = ui.proto[index+1].exp
if (ui.proto[index].exp - haveExp) >= 0 then
botSlider.value = 0
else
local total = (haveExp - ui.proto[index].exp) / ( _next - ui.proto[index].exp)
if total >= 0.5 then
botSlider.value = 1
else
botSlider.value = math.max(total,0)*2
end
end
end