/// Credit setchi (https://github.com/setchi) /// Sourced from - https://github.com/setchi/FancyScrollView using System.Collections.Generic; namespace UnityEngine.UI.Extensions { public abstract class FancyScrollView : MonoBehaviour where TContext : class { [SerializeField, Range(float.Epsilon, 1f)] float cellInterval = 0; [SerializeField, Range(0f, 1f)] float cellOffset = 0; [SerializeField] bool loop = false; [SerializeField] GameObject cellBase = null; [SerializeField] Transform cellContainer = null; readonly List> cells = new List>(); float currentPosition; protected List cellData = new List(); protected TContext Context { get; private set; } /// /// Sets the context. /// /// Context. protected void SetContext(TContext context) { Context = context; for (int i = 0; i < cells.Count; i++) { cells[i].SetContext(context); } } /// /// Updates the contents. /// protected void UpdateContents() { UpdatePosition(currentPosition, true); } /// /// Updates the scroll position. /// /// Position. /// If set to true force update contents. protected void UpdatePosition(float position, bool forceUpdateContents = false) { currentPosition = position; var visibleMinPosition = position - (cellOffset / cellInterval); var firstCellPosition = (Mathf.Ceil(visibleMinPosition) - visibleMinPosition) * cellInterval; var dataStartIndex = Mathf.CeilToInt(visibleMinPosition); var count = 0; for (float p = firstCellPosition; p <= 1f; p += cellInterval, count++) { if (count >= cells.Count) { cells.Add(CreateCell()); } } count = 0; for (float p = firstCellPosition; p <= 1f; p += cellInterval, count++) { var dataIndex = dataStartIndex + count; var cell = cells[GetCircularIndex(dataIndex, cells.Count)]; UpdateCell(cell, dataIndex, forceUpdateContents); if (cell.gameObject.activeSelf) { cell.UpdatePosition(p); } } while (count < cells.Count) { cells[GetCircularIndex(dataStartIndex + count, cells.Count)].SetVisible(false); count++; } } /// /// Updates the cell. /// /// Cell. /// Data index. /// If set to true force update contents. void UpdateCell(FancyScrollViewCell cell, int dataIndex, bool forceUpdateContents = false) { if (loop) { dataIndex = GetCircularIndex(dataIndex, cellData.Count); } else if (dataIndex < 0 || dataIndex > cellData.Count - 1) { // セルに対応するデータが存在しなければセルを表示しない cell.SetVisible(false); return; } if (forceUpdateContents || cell.DataIndex != dataIndex || !cell.IsVisible) { cell.DataIndex = dataIndex; cell.SetVisible(true); cell.UpdateContent(cellData[dataIndex]); } } /// /// Creates the cell. /// /// The cell. FancyScrollViewCell CreateCell() { var cellObject = Instantiate(cellBase, cellContainer); var cell = cellObject.GetComponent>(); cell.SetContext(Context); cell.SetVisible(false); cell.DataIndex = -1; return cell; } /// /// Gets the circular index. /// /// The circular index. /// Index. /// Max size. int GetCircularIndex(int index, int maxSize) { return index < 0 ? maxSize - 1 + (index + 1) % maxSize : index % maxSize; } #if UNITY_EDITOR bool cachedLoop; float cachedCellInterval, cachedCellOffset; void LateUpdate() { if (cachedLoop != loop || cachedCellOffset != cellOffset || cachedCellInterval != cellInterval) { cachedLoop = loop; cachedCellOffset = cellOffset; cachedCellInterval = cellInterval; UpdatePosition(currentPosition); } } #endif } public sealed class FancyScrollViewNullContext { } public abstract class FancyScrollView : FancyScrollView { } }