using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public interface IScrollContent {
int CurrentRecord { get; set; }
int TotalRecords { get; }
void FillContent (GameObject resource, int index);
}
public class ScrollList : MonoBehaviour {
public bool ReuseContent = false;
public GameObject ContentSource = null;
public GameObject ContentTemplate = null;
IScrollContent scrollContent = null;
GameObject[] contentResources = null;
ScrollRect scrollRect = null;
float resourceAnchor = 0f;
Vector2 resourcePadding = Vector2.zero;
int First = 0;
int Last { get { return First + contentResources.Length – 1; } }
int PadCells = 3;
void Initialize() {
scrollContent = ContentSource.GetComponent(typeof(IScrollContent)) as IScrollContent;
scrollRect = GetComponent<ScrollRect>();
int contentCount = TileCount();
ResizeContent();
contentResources = new GameObject[contentCount];
for (int i = 1; i < contentResources.Length; i++)
contentResources[i] = Instantiate(ContentTemplate) as GameObject;
if (contentResources.Length > 0)
contentResources[0] = ContentTemplate;
}
int TileCount () {
if (!ReuseContent) return scrollContent.TotalRecords;
bool horizontal = scrollRect.horizontal;
RectTransform scrollTransform = scrollRect.transform as RectTransform;
RectTransform resourceRect = ContentTemplate.transform as RectTransform;
int fit = horizontal
? (int)(scrollTransform.rect.width / resourceRect.rect.width)
: (int)(scrollTransform.rect.height / resourceRect.rect.height);
fit += PadCells * 2;
return fit;
}
void ResizeContent () {
RectTransform contentRect = scrollRect.content.transform as RectTransform;
RectTransform resourceRect = ContentTemplate.transform as RectTransform;
bool horizontal = scrollRect.horizontal;
int totalRecords = scrollContent.TotalRecords;
float resourceSize = horizontal
? resourceRect.rect.width
: resourceRect.rect.height;
float contentSize = resourceSize * totalRecords;
contentRect.offsetMin = new Vector2(0f, 0f);
contentRect.offsetMax = horizontal
? new Vector2(contentSize – contentRect.rect.width, contentRect.offsetMax.y)
: new Vector2(contentRect.offsetMax.x, contentSize – contentRect.rect.height);
resourceAnchor = resourceSize / contentSize;
resourcePadding = resourceRect.offsetMin;
}
void FillContent(int resource, int index) {
if (index >= 0 && index < scrollContent.TotalRecords) {
contentResources[resource].SetActive(true);
scrollContent.FillContent(contentResources[resource], index);
} else {
contentResources[resource].SetActive(false);
}
}
public void RefreshContent() {
for (int i = 0; i < contentResources.Length; i++) {
FillContent (i, First + i);
}
}
public void ScrollTo(int index) {
if (contentResources == null)
Initialize();
bool horizontal = scrollRect.horizontal;
// center the index (if possible)
First = index – contentResources.Length / 2;
int last = First + contentResources.Length;
if (last > scrollContent.TotalRecords)
First -= (last – scrollContent.TotalRecords);
if (First < 0)
First = 0;
Vector2 indexPos = Vector2.zero;
for (int i = 0; i < contentResources.Length; i++) {
int listPos = First + i;
AssignResource(i, listPos);
if (index == listPos) {
RectTransform resourceRect = contentResources[i].transform as RectTransform;
indexPos = resourceRect.localPosition;
}
}
RectTransform contentRect = scrollRect.content.transform as RectTransform;
float offset = (horizontal ? indexPos.x : –indexPos.y);
Vector2 pos = new Vector2(horizontal ? offset : 0f, horizontal ? 0f : offset);
contentRect.localPosition = pos;
}
void AssignResource (int resource, int index) {
RectTransform resourceRect = contentResources[resource].transform as RectTransform;
resourceRect.SetParent(scrollRect.content.transform);
if (scrollRect.horizontal) {
resourceRect.anchorMin = new Vector2(resourceAnchor * index, 0f);
resourceRect.anchorMax = new Vector2(resourceAnchor * (index + 1), 1f);
} else { // vertical
float min = 1f – (resourceAnchor * (index+1));
float max = 1f – (resourceAnchor * (index));
resourceRect.anchorMin = new Vector2(0f, min);
resourceRect.anchorMax = new Vector2(1f, max);
}
resourceRect.offsetMin = resourcePadding;
resourceRect.offsetMax = –resourcePadding;
FillContent(resource, index);
}
public void DecrementResource () {
if (First <= 0)
return;
Debug.Log(“Decrement: First: “ + First + “ Last: “ + Last + “ Count: “ + contentResources.Length);
int c = contentResources.Length – 1;
GameObject first = contentResources[c];
for (int i = c ; i > 0; i—)
{
contentResources[i] = contentResources[i–1];
}
contentResources[0] = first;
First–;
AssignResource(0, First);
}
public void IncrementResource () {
if (Last >= (scrollContent.TotalRecords–1))
return;
GameObject last = contentResources[0];
int c = contentResources.Length – 1;
for (int i = 0; i < c; i++)
{
contentResources[i] = contentResources[i+1];
}
contentResources[c] = last;
First++;
AssignResource(c, Last);
}
public void OnValueChanged () {
if (scrollRect == null || scrollRect.content == null)
return;
RectTransform contentRect = scrollRect.content.transform as RectTransform;
RectTransform resourceRect = ContentTemplate.transform as RectTransform;
// correct for ends
RectTransform parentRect = scrollRect.transform as RectTransform;
Vector2 position = contentRect.position;
position.y += contentRect.rect.height;
position.y -= (parentRect.rect.height * 1.5f);
position.y += (resourceRect.rect.height * 2f);
Vector2 size = new Vector2(contentRect.rect.width, contentRect.rect.height);
float percent = position.y / size.y;
int calcFirst = (int)(percent * (float)scrollContent.TotalRecords);
calcFirst -= PadCells;
int deltaFirst = calcFirst – First;
while (deltaFirst < –1) {
DecrementResource();
deltaFirst++;
}
while (deltaFirst > 1) {
IncrementResource();
deltaFirst–;
}
}
}