反正实现的效果就是如标题所示了,无限循环的scrollView。注意这里的方法是比较粗浅的,也当抛砖引玉。反正效果是实现了,然后性能也还行。
先看效果:
之所以要实现这种效果,主要是因为scrollview底下的内容量有时候可能会非常的多,比如说物品背包栏,可能包含成千上万个物品。直接使用原生scrollview的话,那性能消耗是蛮夸张的。毕竟屏幕里能显示的内容数量就那么几个,但是却吃那么多的性能多少有点怪。解决这种情况的方法,一种是无限scrollview,就是再显示区域外再多提供两个格子,一个为头部,一个为尾部,不停的调换位置就行了。 另外一种就是分页了,就提供固定几个格子,然后按照分页修改格子的内容。
代码分两个部分,一个与scrollview相关,一个与scrollbar相关。具体的代码分析实在是写的头痛,有需要的话自己看看就行了。不是什么很难的东西。
下边的scrollview的代码:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class UnlimitedScrollView : MonoBehaviour, IEndDragHandler
{
[Header("内容条目的数量")]
public int ItemNum;
[Header("Item高度间隔")]
public int ItemSizeHight;
private RectTransform Content;
private RectTransform[] ShowItem;//Item数组
public Scrollbar VerticalScrollbar;
private float CurrentContentPos;
private int CurrentItemNum;
private int _Downcurrentiemnum;
private int Head, End;
private float viewHight;
[Header("当前显示的数目")]
private int ShowItemNum;
[Header("Item的obj")]
public GameObject ShowItemObj;
// Start is called before the first frame update
void Start()
{
Content = this.GetComponent<ScrollRect>().content;
float ItemHight = ShowItemObj.GetComponent<RectTransform>().sizeDelta.y;
viewHight = this.GetComponent<RectTransform>().sizeDelta.y;
ItemSizeHight = (int)(ItemSizeHight + ItemHight);
ShowItemNum = (int)(viewHight / ItemSizeHight) + 3;//竖向显示的数目
float ContentHight = ItemSizeHight * ItemNum;
Content.GetComponent<RectTransform>().sizeDelta = new Vector2(Content.sizeDelta.x, ContentHight);
CurrentItemNum = 1;
_Downcurrentiemnum = CurrentItemNum;
Init();
CheckItemAndSet();
Head = 0;
End = ShowItem.Length - 1;
if (VerticalScrollbar != null)
{
VerticalScrollbar.onValueChanged.AddListener((float a) => { CheckItemAndSet(); });
VerticalScrollbar.gameObject.AddComponent<MyScrollbar>();
VerticalScrollbar.gameObject.GetComponent<MyScrollbar>().EndDrag.AddListener(() => { CheckItemAndSet(); } );
}//检测有无scrollbar
}
// Update is called once per frame
void Update()
{
CurrentContentPos = Content.anchoredPosition.y - (ItemSizeHight / 2);
CheckItem();
if (CurrentItemNum >= _Downcurrentiemnum + 1)
{
_Downcurrentiemnum = CurrentItemNum;
SwapHeadToEnd();
}
else if (CurrentItemNum <= _Downcurrentiemnum - 1)
{
_Downcurrentiemnum = CurrentItemNum;
SwapEndToHead();
}
}
public void Init()
{
ShowItem = new RectTransform[ShowItemNum];
ShowItem[0] = ShowItemObj.GetComponent<RectTransform>();
for (int i = 0; i < ShowItemNum; i++)
{
GameObject showitemobj = GameObject.Instantiate(ShowItemObj, Content, false);
ShowItem[i] = showitemobj.GetComponent<RectTransform>();
showitemobj.name = ShowItemObj.name + i;
showitemobj.GetComponent<RectTransform>().anchoredPosition = new Vector2(showitemobj.GetComponent<RectTransform>().anchoredPosition.x, -(i) * ItemSizeHight);
}
ShowItemObj.SetActive(false);
}
public void CheckItem()
{
CurrentItemNum = (int)(CurrentContentPos / ItemSizeHight);//当前应该显示的数
}
public void SwapHeadToEnd()
{
ShowItem[Head].anchoredPosition = new Vector2(ShowItem[Head].anchoredPosition.x, ShowItem[End].anchoredPosition.y - ItemSizeHight);
ShowItem[Head].transform.SetAsLastSibling();
// ShowItem[Head].GetComponentInChildren<Text>().text = (CurrentItemNum + ShowItem.Length - 1).ToString();
End = Head;
Head++;
if (Head == ShowItem.Length)
{
Head = 0;
}
}//把头部挪到尾部
public void SwapEndToHead()
{
ShowItem[End].anchoredPosition = new Vector2(ShowItem[End].anchoredPosition.x, ShowItem[Head].anchoredPosition.y + ItemSizeHight);
ShowItem[End].transform.SetAsFirstSibling();
// ShowItem[End].GetComponentInChildren<Text>().text = CurrentItemNum.ToString();
Head = End;
End--;
if (End == -1)
{
End = ShowItem.Length - 1;
}
}//把尾部挪到头部
public void CheckItemAndSet()
{
if (ShowItem[Head].anchoredPosition.y != CurrentItemNum * ItemSizeHight + (ItemSizeHight / 2))
{
int _currentitemnum = CurrentItemNum;
int _head = Head;
for (int i = 0; i < ShowItem.Length; i++)
{
// ShowItem[_head].GetComponentInChildren<Text>().text = _currentitemnum.ToString();
ShowItem[_head].anchoredPosition = new Vector2(ShowItem[_head].anchoredPosition.x, -_currentitemnum * ItemSizeHight + (ItemSizeHight / 2));
_head++;
if (_head == ShowItem.Length)
{
_head = 0;
}
_currentitemnum++;
}
}
}//检查一遍当前的item对应位置,错误的话便重新排序位置,并再次赋值
public void OnEndDrag(PointerEventData eventData)
{
CheckItemAndSet();
}
}
然后是一个scrollbar的代码,就是提供一个监听结束拖拽的事件:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
public class DoEventCall : UnityEvent { }
public class MyScrollbar : MonoBehaviour,IEndDragHandler
{
public DoEventCall EndDrag = new DoEventCall();
public void OnEndDrag(PointerEventData eventData)
{
EndDrag.Invoke();
}
}