[UnityUI]循环滑动列表

原文章:https://blog.csdn.net/lyh916/article/details/46984789

效果图:


使用的是UGUI和DOTween

其中比较关键的是循环滑动和层次排序:

1.循环滑动:这里先假设显示五张图片,分别标记为0,1,2,3,4,那么当向左滑动时,序列就变为1,2,3,4,0,这里先保存4的位置,然后从4开始,4的位置和大小向3渐变,3的位置和大小向2渐变,2的位置和大小向1渐变,1的位置和大小向0渐变,0的位置直接变为原来保存的4的位置。也就是说,当向左滑动时,最左端的那张图片特殊处理,其余的向左推进;当向右滑动时,最右端的那张图片特殊处理,其余的向右推进。


2.层次排序:由于使用的是UGUI,UI的排序跟在Hierarchy的位置有关。如果图片缩放得越小,就认为它越远离屏幕,因此就越靠前,会被后面的图片遮住。注意的是在缩放动画播放时,localScale是不确定的,因此要直接将当前位置的下一个位置的localScale传入,从而计算图片的"深度"。还有就是使用SetSiblingIndex时要完全确定好所有图片的排序。



 
 
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. using DG.Tweening;
  4. public class ScrollView : MonoBehaviour {
  5. public int xOffset = 1; //x轴偏移
  6. public int yOffset = 0; //y轴偏移
  7. public float scale = 0.8f; //缩放倍数
  8. public float time = 0.5f; //偏移与缩放动画的播放时间
  9. private int left; //最左端的编号
  10. private int right; //最右端的编号
  11. public int itemAmount = 5; //展示的图片数
  12. public Vector3 middlePos; //最中间的位置
  13. public GameObject itemPrefab;
  14. private GameObject canvas;
  15. private GameObject[] sortArray;
  16. private List<GameObject> list = new List<GameObject>();
  17. private void InstantiateItem(Vector3 pos,float scale)
  18. {
  19. GameObject go = Instantiate(itemPrefab) as GameObject;
  20. go.transform.SetParent(canvas.transform);
  21. go.transform.localPosition = pos;
  22. go.transform.localScale *= scale;
  23. InsertToSortArray(go, go.transform.localScale.x);
  24. list.Add(go);
  25. }
  26. public void Init()
  27. {
  28. left = 0;
  29. right = itemAmount - 1;
  30. canvas = GameObject.Find( "Canvas");
  31. sortArray = new GameObject[itemAmount];
  32. int oneSideAmount = (itemAmount - 1) / 2;
  33. for( int i = oneSideAmount;i >= 1;i--)
  34. {
  35. Vector3 pos = middlePos + new Vector3(i * xOffset,i * yOffset, 0) * -1;
  36. InstantiateItem(pos,Mathf.Pow(scale,i));
  37. }
  38. InstantiateItem(middlePos, 1);
  39. for( int i = 1;i <= oneSideAmount;i++)
  40. {
  41. Vector3 pos = middlePos + new Vector3(i * xOffset,i * yOffset, 0);
  42. InstantiateItem(pos,Mathf.Pow(scale,i));
  43. }
  44. Sort();
  45. }
  46. /// <summary>
  47. /// 根据缩放倍数计算深度
  48. /// </summary>
  49. /// <param name="scaleNum"></param>
  50. /// <returns></returns>
  51. private int CalculateDepth(float scaleNum)
  52. {
  53. float num = 0;
  54. int i = 0;
  55. while ( true)
  56. {
  57. num = Mathf.Pow(scale, i);
  58. if (num != scaleNum) i++;
  59. else break;
  60. }
  61. return i;
  62. }
  63. /// <summary>
  64. /// 插入到排序数组中,数组序号越低,则越远离屏幕
  65. /// </summary>
  66. /// <param name="go"></param>
  67. /// <param name="localScaleX"></param>
  68. private void InsertToSortArray(GameObject go, float localScaleX)
  69. {
  70. int depth = CalculateDepth(localScaleX);
  71. depth = itemAmount / 2 - depth;
  72. if (depth == itemAmount / 2)
  73. sortArray[depth * 2] = go;
  74. else if (sortArray[depth] == null)
  75. sortArray[depth] = go;
  76. else
  77. sortArray[depth + itemAmount / 2] = go;
  78. }
  79. private void Sort()
  80. {
  81. for ( int i = 0; i < itemAmount; i++)
  82. {
  83. sortArray[i].transform.SetSiblingIndex(i);
  84. }
  85. sortArray = new GameObject[itemAmount];
  86. }
  87. public void Move(int direction)
  88. {
  89. if(direction == -1) //向左滑动
  90. {
  91. int startIndex = left;
  92. int lastIndex = right;
  93. Vector3 lastPos = list[lastIndex].transform.position;
  94. InsertToSortArray(list[startIndex], list[startIndex].transform.localScale.x);
  95. for ( int i = 0; i < itemAmount - 1;i++ )
  96. {
  97. int index = (lastIndex - i + itemAmount) % itemAmount;
  98. int preIndex = (index - 1 + itemAmount) % itemAmount;
  99. list[index].transform.DOMove(list[preIndex].transform.position,time);
  100. list[index].transform.DOScale(list[preIndex].transform.localScale,time);
  101. InsertToSortArray(list[index], list[preIndex].transform.localScale.x);
  102. }
  103. list[startIndex].transform.DOMove(lastPos,time);
  104. left = (left + 1) % itemAmount;
  105. right = (right + 1) % itemAmount;
  106. }
  107. else if (direction == 1) //向右滑动
  108. {
  109. int startIndex = right;
  110. int lastIndex = left;
  111. Vector3 lastPos = list[lastIndex].transform.position;
  112. InsertToSortArray(list[startIndex], list[startIndex].transform.localScale.x);
  113. for ( int i = 0; i < itemAmount - 1; i++)
  114. {
  115. int index = (lastIndex + i + itemAmount) % itemAmount;
  116. int preIndex = (index + 1 + itemAmount) % itemAmount;
  117. list[index].transform.DOMove(list[preIndex].transform.position, time);
  118. list[index].transform.DOScale(list[preIndex].transform.localScale, time);
  119. InsertToSortArray(list[index], list[preIndex].transform.localScale.x);
  120. }
  121. list[startIndex].transform.DOMove(lastPos, time);
  122. left = (left - 1 + itemAmount) % itemAmount;
  123. right = (right - 1 + itemAmount) % itemAmount;
  124. }
  125. Sort();
  126. }
  127. }

不足之处:

1.只适用于展示图片数为奇数的场合

2.等等...

Unity 中实现循环滑动列表可以使用 ScrollRect 组件和 ContentSizeFitter 组件。以下是一个基本的步骤: 1. 创建一个空白 GameObject,并向其中添加 ScrollRect 组件。 2. 在 ScrollRect 组件中设置 Content 属性为一个包含所有列表项的 GameObject。 3. 向 Content 中添加一个 VerticalLayoutGroup 组件,用于设置列表项的垂直布局。 4. 向每个列表项 GameObject 中添加一个 LayoutElement 组件,用于设置列表项的高度。 5. 向 ScrollRect 中添加一个 ContentSizeFitter 组件,并将 Vertical Fit 设置为 Preferred Size。 6. 编写一个脚本,用于控制滑动列表循环滚动。该脚本应该包含以下步骤: - 在 Start() 方法中获取列表项的总数和高度。 - 在 Update() 方法中检查 ScrollRect 是否已经滚动到列表的顶部或底部,并相应地更新 Content 的位置以实现循环滚动。 下面是一个简单的示例代码: ```csharp using UnityEngine; using UnityEngine.UI; public class LoopScroll : MonoBehaviour { public float itemHeight; // 列表项的高度 public int itemCount; // 列表项的总数 private RectTransform content; private ScrollRect scrollRect; private float contentHeight; private void Start() { content = GetComponent<ScrollRect>().content; scrollRect = GetComponent<ScrollRect>(); contentHeight = itemHeight * itemCount; content.sizeDelta = new Vector2(content.sizeDelta.x, contentHeight); } private void Update() { if (scrollRect.verticalNormalizedPosition <= 0f) { content.anchoredPosition = new Vector2(content.anchoredPosition.x, content.anchoredPosition.y + contentHeight); scrollRect.verticalNormalizedPosition = 1f; } else if (scrollRect.verticalNormalizedPosition >= 1f) { content.anchoredPosition = new Vector2(content.anchoredPosition.x, content.anchoredPosition.y - contentHeight); scrollRect.verticalNormalizedPosition = 0f; } } } ``` 在这个示例中,我们在 Start() 方法中计算了 Content 的总高度,并在 Update() 方法中检查 ScrollRect 是否已经滚动到列表的顶部或底部。如果是,我们就相应地更新 Content 的位置以实现循环滚动。注意,我们还将 ScrollRect 的 verticalNormalizedPosition 设置为 0f 或 1f,以保持滚动位置不变。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值