在做UI scrollrect的时候,有的时候因为数据很多,要是每个单位的数据都做成一个scrollrect element的话,会造成无畏的内存浪费,那些不显示的element 其实没有必要提前创建。
那么怎么解决这个问题呢?
我们可以做一个只能的scrollrect 控制器,用一个有限的scrollrect element组来显示无限的scrollrect 数据,只要这些scrollrect element RectTransform可以重新定位,及时更新显示的数据,那就可以用少量的scrollrect element RectTransform来模拟无限多的效果。
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
namespace LDFW.UI {
[RequireComponent(typeof(ScrollRect))]
public class InfiniteScrollRectController : MonoBehaviour {
public List<int> _data;
public ScrollRect _scrollRect;
public RectTransform _scrollRectContent;
public RectTransform _scrollRectElementParentContent;
public int _scrollRectElementPreferredHeight = 100;
private int _contentStartDataIndex;
private int _contentEndDataIndex;
private int _lastActiveIndex;
private int _dataLength;
private int _contentElementCount;
private float _contentTopActionPosition;
private float _contentBottomActionPosition;
void Awake () {
_scrollRect.onValueChanged.AddListener (OnScrollRectContentValueChanged);
}
void Start () {
Test ();
}
void Test () {
_data = new List<int> ();
for (int i=0; i<100; i++) {
_data.Add (i);
}
LoadData ();
}
public virtual void Reset () {
if (_scrollRect == null || _scrollRectContent == null || _scrollRectElementParentContent == null) {
Debug.LogError ("Missing scroll rect info!");
return;
}
_scrollRectContent.anchorMin = new Vector2 (0, 1);
_scrollRectContent.anchorMax = new Vector2 (1, 1);
_scrollRectContent.pivot = new Vector2 (0.5f, 1f);
_scrollRectContent.sizeDelta = new Vector2 (_scrollRectContent.sizeDelta.x, _data.Count * _scrollRectElementPreferredHeight);
_scrollRectElementParentContent.anchorMin = new Vector2 (0, 1);
_scrollRectElementParentContent.anchorMax = new Vector2 (1, 1);
_scrollRectElementParentContent.pivot = new Vector2 (0.5f, 1f);
for (int i = 0; i < _scrollRectElementParentContent.childCount; i++) {
if (_scrollRectElementParentContent.GetChild (i).GetComponent<LayoutElement> () == null) {
_scrollRectElementParentContent.GetChild (i).gameObject.AddComponent<LayoutElement> ();
}
_scrollRectElementParentContent.GetChild (i).GetComponent<LayoutElement> ().preferredHeight = _scrollRectElementPreferredHeight;
}
_contentTopActionPosition = _scrollRectElementPreferredHeight * 1.5f;
_contentBottomActionPosition = _scrollRectElementPreferredHeight * (_scrollRectElementParentContent.childCount - 1.5f) - _scrollRect.viewport.rect.height;
Debug.Log ("top and bottom = " + _contentTopActionPosition + ", " + _contentBottomActionPosition);
_contentStartDataIndex = 0;
_contentEndDataIndex = 0;
_lastActiveIndex = 0;
_dataLength = _data.Count;
_contentElementCount = _scrollRectElementParentContent.childCount;
}
public virtual void LoadData () {
Reset ();
for (int i = 0; i < _contentElementCount; i++) {
if (i >= _dataLength) {
_scrollRectElementParentContent.GetChild (i).gameObject.SetActive (false);
} else {
_scrollRectElementParentContent.GetChild (i).gameObject.SetActive (true);
_contentStartDataIndex = 0;
_contentEndDataIndex = i;
_lastActiveIndex = i;
_scrollRectElementParentContent.GetChild (i).GetComponent<Text> ().text = "Index " + i;
}
}
}
public virtual void LoadDataIntoScrollRectElement (int dataIndex, int scrollRectElementIndex) {
if (dataIndex < _dataLength && scrollRectElementIndex < _contentElementCount) {
_scrollRectElementParentContent.GetChild (scrollRectElementIndex).GetComponent<Text> ().text = "Index = " + dataIndex;
}
}
public virtual void OnScrollRectContentValueChanged (Vector2 scrollVector) {
if (_scrollRectContent.anchoredPosition.y < _contentTopActionPosition) {
ContentTopAction ();
} else if (_scrollRectContent.anchoredPosition.y > _contentBottomActionPosition) {
ContentBottomAction ();
}
}
public virtual void ContentTopAction () {
if (_lastActiveIndex >= _contentElementCount - 1) {
if (_contentStartDataIndex > 0) {
_scrollRectElementParentContent.GetChild (_contentElementCount - 1).SetAsFirstSibling ();
_scrollRectElementParentContent.anchoredPosition += new Vector2 (0f, _scrollRectElementPreferredHeight);
_contentTopActionPosition -= _scrollRectElementPreferredHeight;
_contentBottomActionPosition -= _scrollRectElementPreferredHeight;
_contentStartDataIndex--;
_contentEndDataIndex--;
LoadDataIntoScrollRectElement (_contentStartDataIndex, 0);
}
}
}
public virtual void ContentBottomAction () {
if (_lastActiveIndex >= _contentElementCount - 1) {
if (_contentEndDataIndex < _dataLength - 1) {
_scrollRectElementParentContent.GetChild (0).SetAsLastSibling ();
_scrollRectElementParentContent.anchoredPosition -= new Vector2 (0f, _scrollRectElementPreferredHeight);
_contentTopActionPosition += _scrollRectElementPreferredHeight;
_contentBottomActionPosition += _scrollRectElementPreferredHeight;
_contentStartDataIndex++;
_contentEndDataIndex++;
LoadDataIntoScrollRectElement (_contentEndDataIndex, _contentElementCount - 1);
}
}
}
}
}
在每一次更新位置的时候,我们通过程序来判断当前显示的数据index,然后来判断是否需要更新当前的显示数据以及是否需要更新当前的element位置
下面是一些设置截图
在上面的例子里,我们可以只有9个scrollrect element来显示超过100个单位的数据,做成有100个scrollrect element在滚动的效果