前言:项目准备新增一个竞技场排行榜,策划规定只显示0-400名的玩家。我一想,生成四百个游戏物体,怕不是得把手机给卡死?回想原来在GitHub上看到过一个实现思路就是无限循环列表,所以就想自己试试。公司用的是NGUI,花了1个多小时还是没做出来,但是基本思路有了,又到了下班时间,不想赖在公司怕带坏了风气,就回来用自己电脑上的UGUI实现。

实现思路:假设屏幕只显示五行玩家排名,那么就预备十行,上面多两行,下面多三行。每次移动单位距离(一行玩家排名占高),就移动一端的物体到另一端,这样就实现了无限循环。

实现过程:

一、搭建UI

1.先在UI搭建好面板,其中SV物体添加RectMask2D组件,模拟ScrollView的裁剪;将无限循环列表脚本挂在SV上

2.在SV下添加一个Grid(Grid并非组件而是名字)物体,用于模拟移动整个列表

3.Grid物体下添加十个Item,前面隐藏两个,中间显示五个,后面隐藏三个。为什么要多放几个呢?因为想滑动时更加顺滑

二、实现LoopScroll类

1.类中包含字段int[] keys,用于记录下标变换;Dictionary<int,Transform> dic,用于保存下标与Transform之间的映射关系;int gap,用于计算Transform之间应该间隔的距离

2.类中包含方法DownMove(),列表下移时调用;UpMove(),列表上移时调用

public class LoopScroll
{
private Dictionary<int, Transform> dic;
private int[] keys;
private float gap = 0;
public LoopScroll(float gap,params Transform[] items)
{
this.gap = gap;
dic = new Dictionary<int, Transform>(items.Length);
keys = new int[items.Length];
for (int i = 0; i < items.Length; i++)
{
dic.Add(i, items[i]);
keys[i] = i;
}
}
private LoopScroll()
{ } public void DownMove()
{
//TODO 将顶部Trs移动到尾部
int top = keys[0];
for (int i = 0; i < keys.Length-1; i++)
{
keys[i] = keys[i + 1];
}
keys[keys.Length - 1] = top;
int key = keys[keys.Length - 2];
Vector3 pos = dic[top].localPosition;
pos.Set(pos.x, dic[key].localPosition.y - gap, pos.z);
dic[top].localPosition = pos;
} public void UpMove()
{
//TODO 将尾部Trs移动到顶部
int down = keys[keys.Length - 1];
for (int i = keys.Length-1; i > 0; i--)
{
keys[i] = keys[i - 1];
}
keys[0] = down;
int key = keys[1];
Vector3 pos = dic[down].localPosition;
pos.Set(pos.x, dic[key].localPosition.y+gap, pos.z);
dic[down].localPosition = pos;
}
}

讲解:每次移动时,对keys做循环类似的操作,操作完keys后,再通过下标获取对应的Transform,将Transform插入到对应的Position。为什么不直接用Transform[] 数组处理呢?因为我担心移动时会出现,因引用类型的特性,而导致位置混乱,还不如多用一个keys,keys是值类型,操作简单。

三、具体实现

1.因为我是自己做的滑动,所以代码里需要自己写。当按下鼠标左键,并且拖动一定距离时,触发移动方法。在移动方法中判断移动的偏移值的正负性,是向上?还是向下?然后move的position是加还是减?

2.move移动后,判断move移动的距离是否大于等于单位距离(一个item的高),如果移动了单位距离,则触发循环方法。移动的距离是正还是负?可得知是执行DownMove还是UpMove。

public class TestDragScroll : MonoBehaviour
{
public Transform startItem;
public List<Transform> listTrs;
public Transform move;
private const float GAPY = 110f;
private const float PerMoveDetal = 110f;
private LoopScroll scorll; private float prePosY; private float movePrePosY; private void OnValidate()
{
Vector3 startPos = startItem.localPosition;
float startY = startPos.y;
for (int i = 0; i < listTrs.Count; i++)
{
listTrs[i].localPosition = new Vector3(startPos.x, startY, startPos.z);
startY -= GAPY;
}
}
// Start is called before the first frame update
void Start()
{
scorll = new LoopScroll(GAPY, listTrs.ToArray());
prePosY = Input.mousePosition.y;
movePrePosY = move.localPosition.y;
} // Update is called once per frame
void Update()
{
if (Input.GetMouseButton(0))
{
float detal = Input.mousePosition.y - prePosY;
if (Mathf.Abs(detal)>=1f)
{
prePosY = Input.mousePosition.y;
Vector3 pos = move.localPosition;
if (detal>0)
{
pos.Set(pos.x, pos.y + 4f, pos.z);
}
else
{
pos.Set(pos.x, pos.y - 4f, pos.z);
}
move.localPosition = pos;
}
} float moveDetal = move.localPosition.y - movePrePosY;
if (Mathf.Abs(moveDetal)>=PerMoveDetal)
{
if (moveDetal>0)
{
scorll.DownMove();
Debug.Log("Down");
}
else
{
scorll.UpMove();
Debug.Log("Up");
}
movePrePosY = move.localPosition.y;
}
}
}

四、项目实现效果

在自己电脑上用UGUI实现了并非适合项目场景。最终实现时,因为Update中判断移动距离的方法并不可靠,移动距离每次不可能都=113,而我的判断时只要>=113就执行一次循环,那么我滑动226呢?还是只移动了一个item。所以此方法行不通。我的主程告诉我,400个item并不一定要用无限循环列表,如果短时间内做不出来就不要再做了,项目进度要紧。建议我用协程分帧生成400个item,不会卡住的。由于我心烦气乱,最终没有做循环列表的方案。

但是循环列表的雏形是有的,以前都只知道循环列表的思路而未真正实现过,这次实践是第一次,收获颇丰,特写随笔记录

最新文章

  1. 一起学微软Power BI系列-使用技巧(3)Power BI安卓手机版安装与体验
  2. ASP.NET Web API路由系统:Web Host下的URL路由
  3. [ASP.NET MVC 小牛之路]11 - Filter
  4. 文件编码、charset、sublime编辑器支持GBK等问题
  5. Oracle 数据库SQL性能查看
  6. SinalR+WebSocket
  7. 卫星轨道和两行数据TLE
  8. jsb里出现的 Invalid Native Object的一次bug修复的思考
  9. Mysql中的Prepared Statement与Stored Precedure学习
  10. Spring MVC Controller中GET方式传过来的中文参数会乱码的问题
  11. 【python】闰年规则
  12. C中的宏
  13. 基于visual Studio2013解决算法导论之008快速排序算法
  14. MailTest
  15. docker hub切换国内镜像
  16. eureka ... is an unknown property 在 application.properties 中
  17. RabbitMQ简单应用の简单队列
  18. LDO选型注意事项
  19. The type java.lang.Object cannot be resolved
  20. windows2012任务计划不执行

热门文章

  1. java的内存泄露是如何发生的,如何避免和发现
  2. 没有高度的div中的子元素高度自动撑开
  3. VUE-SSR原理和使用
  4. vue上拉加载下拉加载
  5. 设计模式之:享元模式FlyweightPattern的实现
  6. 使用SQL的FOR XML PATH(&#39;&#39;)将字段用逗号隔开
  7. 帝国CMS灵动标签调用包含指定短语关键词关键字文章的语法
  8. Alibaba Java诊断工具Arthas查看Dubbo动态代理类
  9. Elasticsearch上手指南
  10. Educational Codeforces Round 121 (Rated for Div. 2)——A - Equidistant Letters