温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Unity ScrollView如何实现无限循环效果

发布时间:2021-07-27 13:44:13 来源:亿速云 阅读:504 作者:小新 栏目:开发技术

小编给大家分享一下Unity ScrollView如何实现无限循环效果,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

具体内容如下

在Unity引擎中ScrollView组件是一个使用率比较高的组件,该组件能上下或者左右拖动的UI列表,背包、展示多个按钮等情况的时候会用到,在做排行榜类似界面时,item非常多,可能有几百个,一次创建这么多GameObject是非常卡的。为此,使用只创建可视区一共显示的个数,加上后置准备个数。

由于ScrollView有两种滚动方式,水平滚动或者垂直滚动,所以我创建了ScrollBase基类,和HorizontalScroll子类及VerticalScroll子类,在父类中设定了公共的抽象方法OnDrawView—绘制显示区的方法;CreateItem----创建Item的方法;Update----滚动状态下实时更新Item的位置。

ScrollBase基类

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public enum MoveType {     UP,     DOWN,     LEFT,     RIGHT,     STOP } public abstract class ScrollBase {     public ItemArray<ItemData> items;     public ScrollViewLoop scrollLoop;     public float viewHeight;     public float viewWidth;     public float contentHeight;     public float contentWidth;     public RectTransform rectTransform;     public ScrollRect scrollRect;     public MoveType type;     public float item_width;//每个Item的宽度     public float item_height;//每个Item的高度     public int viewNum;//显示区显示的个数     public int addNum;//后置准备个数     public int itemNum;//总共需要多少Item的滚动     public float spaceY;//垂直Item间隔     public float spaceX;//水平Item间隔     public ScrollBase(ScrollViewLoop _scrollLoop, bool isCreateItem = true)     {         scrollLoop = _scrollLoop;         rectTransform = scrollLoop.GetComponent<RectTransform>();         scrollRect = scrollLoop.GetComponent<ScrollRect>();         if (!scrollRect)         {             scrollRect = scrollLoop.gameObject.AddComponent<ScrollRect>();         }         item_width = scrollLoop.item_width;         item_height = scrollLoop.item_height;         viewNum = scrollLoop.viewNum;         addNum = scrollLoop.addNum;         itemNum = scrollLoop.itemNum;         spaceY = scrollLoop.spaceY;         spaceX = scrollLoop.spaceX;         OnDrawView();         if (isCreateItem)         {             CreateItem();         }     }     public abstract void OnDrawView();     public abstract void CreateItem();     public abstract void Update(); }

ScrollViewLoop控制类

这个属性类需要挂载在ScrollRect物体身上,然后在面板上进行属性配置

using System.Collections; using System.Collections.Generic; using UnityEngine; public class ItemData {     public RectTransform itemRect;     public int index; } public class ScrollViewLoop : MonoBehaviour {     public GameObject itemPrefab;     [Header("每个Item的宽度")]     public float item_width;     [Header("每个Item的高度")]     public float item_height;     [Header("显示区显示几个Item")]     public int viewNum = 6;     [Header("显示区外多复制几个Item")]     public int addNum = 2;     [Header("总共需要多少Item")]     public int itemNum = 100;     [Header("Item之间的垂直距离")]     public float spaceY = 2;     public float spaceX = 2;     public delegate void ItemChange(ItemData itemData);     public event ItemChange OnChange;//Item位置改变时调用的事件     [Header("是否是横向滑动")]     public bool isHorizontal = false;     ScrollBase scrollBase;     void Start()     {         if (isHorizontal)         {             scrollBase = new HorizontalScroll(this);         }         else         {             scrollBase = new VerticalScroll(this);         }     }     public void UseOnChange(ItemData itemData)     {         OnChange?.Invoke(itemData);     }         //ScrollRect滚动     void Update()     {         if (scrollBase != null)         {             scrollBase.Update();         }     } }

ItemArray

Unity ScrollView如何实现无限循环效果

我们实现无限循环的核心思想是,当滚动框向左移动时,就判断左边的第一个Item距离显示框左边框的距离,是否大于Item水平间隔*0.5+Item的宽度,如果大于则把第一个Item放到最后的位置,当滚动框向右移动时就判断右边的Item距离右边框的距离情况,这样我们就可以在显示区域一直看到有Item的规则显示,所以我定制了一个泛型容器类,这个类存放所有的Item信息,当我们取第一个Item时自动把第一个Item放到最后,当我们取最后一个Item时自动把最后的一个Item放到最前面。

using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// Item集合类 /// </summary> /// <typeparam name="T"></typeparam> public class ItemArray<T> where T : ItemData {     List<T> list;     public int count     {         get         {             return list.Count;         }     }     public ItemArray()     {         list = new List<T>();     }     public ItemArray(T[] ts)     {         if (ts == null)         {             return;         }         for (int i = 0; i < ts.Length; i++)         {             list.Add(ts[i]);         }     }     /// <summary>     /// 添加一个元素     /// </summary>     /// <param name="t"></param>     public void AddItem(T t)     {         list.Add(t);     }     public T GetFirst()     {         if (list.Count == 0)         {             return default(T);         }         T t = list[0];         list.RemoveAt(0);         t.index = list[list.Count - 1].index + 1;         list.Add(t);         return t;     }     public T GetLast()     {         if (list.Count == 0)         {             return default(T);         }         T t = list[list.Count - 1];         list.RemoveAt(list.Count - 1);         t.index = list[0].index - 1;         list.Insert(0, t);         return t;     }     public T[] GetArray()     {         T[] ts = new T[list.Count];         for (int i = 0; i < list.Count; i++)         {             ts[i] = list[i];         }         return ts;     }     public T this[int index]     {         get         {             return list[index];         }     } }

HorizontalScroll子类及VerticalScroll子类

ScrollView无限循环的核心功能代码都在这两个子类中

HorizontalScroll子类

using System.Collections; using System.Collections.Generic; using UnityEngine; public class HorizontalScroll : ScrollBase {     public HorizontalScroll(ScrollViewLoop _scrollLoop, bool isCreateItem = true) : base(_scrollLoop, isCreateItem)     {         scrollRect.horizontal = true;         scrollRect.vertical = false;     }     public override void CreateItem()     {         items = new ItemArray<ItemData>();         for (int i = 0; i < viewNum + addNum; i++)         {             GameObject item = GameObject.Instantiate(scrollLoop.itemPrefab);             RectTransform itemRect = item.GetComponent<RectTransform>();             ItemData data = new ItemData();             data.itemRect = itemRect;             data.index = i;             items.AddItem(data);             scrollLoop.UseOnChange(data);             itemRect.sizeDelta = new Vector2(item_width, item_height);             itemRect.anchorMin = new Vector2(0, 1);             itemRect.anchorMax = new Vector2(0, 1);             itemRect.pivot = new Vector2(0, 1);             itemRect.localScale = Vector2.one;             item.transform.parent = scrollRect.content;             item.transform.localPosition = new Vector3(i * (item_width + spaceX), 0, 0);         }     }     void RewindItemPos()     {         int index = Mathf.FloorToInt(Mathf.Abs(scrollRect.content.localPosition.x) / (item_width + spaceX));         for (int i = 0; i < items.count; i++)         {             RectTransform itemRect = items[i].itemRect;             items[i].index = index;             scrollLoop.UseOnChange(items[i]);             itemRect.transform.localPosition = new Vector3(items[i].index * (item_width + spaceX), 0, 0);             index++;         }     }     public override void OnDrawView()     {         SetRectTransform(rectTransform);         rectTransform.sizeDelta = new Vector2(item_width * viewNum + (viewNum - 1) * spaceX, item_height);         SetRectTransform(scrollRect.viewport);         viewHeight = scrollLoop.item_height;         viewWidth = viewNum * item_width + (viewNum - 1) * spaceX;         scrollRect.viewport.sizeDelta = new Vector2(viewWidth, viewHeight);         scrollRect.viewport.localPosition = Vector3.zero;         SetRectTransform(scrollRect.content);         contentHeight = item_height;         contentWidth = itemNum * item_width + (itemNum - 1) * spaceX;         scrollRect.content.sizeDelta = new Vector2(contentWidth, contentHeight);         scrollRect.content.localPosition = Vector3.zero;     }     public void SetRectTransform(RectTransform rect)     {         rect.anchorMin = new Vector2(0, 0.5f);         rect.anchorMax = new Vector2(0, 0.5f);         rect.pivot = new Vector2(0, 1);         rect.localScale = Vector2.one;     }     float lastX = 0;     MoveType lastMoveType = MoveType.STOP;     public override void Update()     {         float x = scrollRect.content.localPosition.x;         if (x > lastX)         {             type = MoveType.RIGHT;         }         else if (x < lastX)         {             type = MoveType.LEFT;         }         else         {             type = MoveType.STOP;             if (lastMoveType != type)             {                 Debug.Log("重置位置");                 RewindItemPos();             }         }         if (type == MoveType.LEFT)//向左滑动         {             if (items[items.count - 1].index == itemNum - 1)             {                 return;             }             float firstItemX = items[0].itemRect.localPosition.x;             if (-x - firstItemX - item_width >= spaceX * 0.5f)             {                 float lastItemX = items[items.count - 1].itemRect.localPosition.x;                 ItemData firstItem = items.GetFirst();                 firstItem.itemRect.localPosition = new Vector3(lastItemX + spaceX + item_width, 0, 0);                 if (firstItem.index < itemNum)                 {                     scrollLoop.UseOnChange(firstItem);                 }             }         }         else if (type == MoveType.RIGHT)//向右滑动         {             if (items[0].index == 0)             {                 return;             }             float lastItemX = items[items.count - 1].itemRect.localPosition.x;             if (lastItemX + x - viewWidth >= spaceX * 0.5f)             {                 float firstItemX = items[0].itemRect.localPosition.x;                 ItemData lastItem = items.GetLast();                 lastItem.itemRect.localPosition = new Vector3(firstItemX - spaceX - item_width, 0, 0);                 if (lastItem.index >= 0)                 {                     scrollLoop.UseOnChange(lastItem);                 }             }         }         lastMoveType = type;         lastX = x;     } }

VerticalScroll子类

using System.Collections; using System.Collections.Generic; using UnityEngine; public class VerticalScroll : ScrollBase {     public VerticalScroll(ScrollViewLoop _scrollLoop, bool isCreateItem = true) : base(_scrollLoop, isCreateItem)     {         scrollRect.horizontal = false;         scrollRect.vertical = true;     }     public override void CreateItem()     {         items = new ItemArray<ItemData>();         for (int i = 0; i < viewNum + addNum; i++)         {             GameObject item = GameObject.Instantiate(scrollLoop.itemPrefab);             RectTransform itemRect = item.GetComponent<RectTransform>();             ItemData data = new ItemData();             data.itemRect = itemRect;             data.index = i;             items.AddItem(data);             scrollLoop.UseOnChange(data);             itemRect.sizeDelta = new Vector2(item_width, item_height);             itemRect.anchorMin = new Vector2(0, 1);             itemRect.anchorMax = new Vector2(0, 1);             itemRect.pivot = new Vector2(0, 1);             itemRect.localScale = Vector2.one;             item.transform.parent = scrollRect.content;             item.transform.localPosition = new Vector3(0, (-i) * (item_height + spaceY), 0);         }     }     void RewindItemPos()     {         int index = Mathf.FloorToInt(Mathf.Abs(scrollRect.content.localPosition.y) / (item_height + spaceY));         for (int i = 0; i < items.count; i++)         {             RectTransform itemRect = items[i].itemRect;             items[i].index = index;             scrollLoop.UseOnChange(items[i]);             itemRect.transform.localPosition = new Vector3(0, (-items[i].index) * (item_height + spaceY), 0);             index++;         }     }     public override void OnDrawView()     {         SetRectTransform(rectTransform);         rectTransform.sizeDelta = new Vector2(item_width, viewNum * item_height + (viewNum - 1) * spaceY);         SetRectTransform(scrollRect.viewport);         viewHeight = viewNum * item_height + (viewNum - 1) * spaceY;         scrollRect.viewport.sizeDelta = new Vector2(item_width, viewHeight);         scrollRect.viewport.localPosition = Vector3.zero;         SetRectTransform(scrollRect.content);         contentHeight = itemNum * item_height + (itemNum - 1) * spaceY;         scrollRect.content.sizeDelta = new Vector2(item_width, contentHeight);         scrollRect.content.localPosition = Vector3.zero;     }     public void SetRectTransform(RectTransform rect)     {         rect.anchorMin = new Vector2(0.5f, 1);         rect.anchorMax = new Vector2(0.5f, 1);         rect.pivot = new Vector2(0, 1);         rect.localScale = Vector2.one;     }     float lastY = 0;     MoveType lastMoveType = MoveType.STOP;     public override void Update()     {         float y = scrollRect.content.localPosition.y;         if (y > lastY)         {             type = MoveType.UP;         }         else if (y < lastY)         {             type = MoveType.DOWN;         }         else         {             type = MoveType.STOP;             if (lastMoveType != type)             {                 RewindItemPos();             }         }         if (type == MoveType.UP)//向上滑动         {             if (items[items.count - 1].index == itemNum - 1)             {                 return;             }             float firstItemY = items[0].itemRect.localPosition.y;             if (firstItemY - item_height + y >= spaceY * 0.5f)             {                 float lastItemY = items[items.count - 1].itemRect.localPosition.y;                 ItemData firstItem = items.GetFirst();                 firstItem.itemRect.localPosition = new Vector3(0, lastItemY - spaceY - item_height, 0);                 if (firstItem.index < itemNum)                 {                     scrollLoop.UseOnChange(firstItem);                 }             }         }         else if (type == MoveType.DOWN)//向下滑动         {             if (items[0].index == 0)             {                 return;             }             float lastItemY = items[items.count - 1].itemRect.localPosition.y;             if (-lastItemY - y - viewHeight >= spaceY * 0.5f)             {                 float firstItemY = items[0].itemRect.localPosition.y;                 ItemData lastItem = items.GetLast();                 lastItem.itemRect.localPosition = new Vector3(0, firstItemY + spaceY + item_height, 0);                 if (lastItem.index >= 0)                 {                     scrollLoop.UseOnChange(lastItem);                 }             }         }         lastMoveType = type;         lastY = y;     } }

编辑器拓展

这一步我们进行编辑器的拓展,根据ScrollViewLoop控制类面板上的数据我们在未运行的状态下改变ScrollView的显示区域,这样更利于我们的可视化排版。

using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityEngine.UI; [CustomEditor(typeof(ScrollViewLoop))] public class ScrollLopEditor : Editor {     ScrollViewLoop scrollLoop;     private RectTransform scrollRectTransfrom;     private ScrollRect scrollRect;     private void OnEnable()     {         scrollLoop = target as ScrollViewLoop;         scrollRectTransfrom = scrollLoop.GetComponent<RectTransform>();         scrollRect = scrollLoop.GetComponent<ScrollRect>();     }     public override void OnInspectorGUI()     {         base.OnInspectorGUI();         bool isBtn = GUILayout.Button("编辑ScrollView显示区大小");         if (isBtn)         {             if (scrollLoop.isHorizontal)             {                 ScrollBase scrollBase = new HorizontalScroll(scrollLoop, false);             }             else             {                 ScrollBase scrollBase = new VerticalScroll(scrollLoop, false);             }         }     } }

测试

测试一下功能效果

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class Test : MonoBehaviour {     public ScrollViewLoop sl;     private void Start()     {         sl.OnChange += Sl_OnChange;     }     //Item位置改变时自动改变Item展示内容     private void Sl_OnChange(ItemData itemData)     {         itemData.itemRect.GetChild(0).GetComponent<Text>().text = "ITEM"+itemData.index;     } }

面板显示如下:

Unity ScrollView如何实现无限循环效果

运行效果如下(本来想放一段视频的,遗憾的是没能成功操作,尴尬):

Unity ScrollView如何实现无限循环效果

以上是“Unity ScrollView如何实现无限循环效果”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI