com.unity.uiextensions/Scripts/Layout/FancyScrollView.cs

172 lines
5.4 KiB
C#
Raw Normal View History

/// 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<TData, TContext> : MonoBehaviour where TContext : class
{
[SerializeField, Range(float.Epsilon, 1f)]
float cellInterval;
[SerializeField, Range(0f, 1f)]
float cellOffset;
[SerializeField]
bool loop;
[SerializeField]
GameObject cellBase;
[SerializeField]
Transform cellContainer;
readonly List<FancyScrollViewCell<TData, TContext>> cells = new List<FancyScrollViewCell<TData, TContext>>();
float currentPosition;
protected List<TData> cellData = new List<TData>();
protected TContext Context { get; private set; }
/// <summary>
/// Sets the context.
/// </summary>
/// <param name="context">Context.</param>
protected void SetContext(TContext context)
{
Context = context;
for (int i = 0; i < cells.Count; i++)
{
cells[i].SetContext(context);
}
}
/// <summary>
/// Updates the contents.
/// </summary>
protected void UpdateContents()
{
UpdatePosition(currentPosition, true);
}
/// <summary>
/// Updates the scroll position.
/// </summary>
/// <param name="position">Position.</param>
/// <param name="forceUpdateContents">If set to <c>true</c> force update contents.</param>
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++;
}
}
/// <summary>
/// Updates the cell.
/// </summary>
/// <param name="cell">Cell.</param>
/// <param name="dataIndex">Data index.</param>
/// <param name="forceUpdateContents">If set to <c>true</c> force update contents.</param>
void UpdateCell(FancyScrollViewCell<TData, TContext> 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]);
}
}
/// <summary>
/// Creates the cell.
/// </summary>
/// <returns>The cell.</returns>
FancyScrollViewCell<TData, TContext> CreateCell()
{
var cellObject = Instantiate(cellBase, cellContainer);
var cell = cellObject.GetComponent<FancyScrollViewCell<TData, TContext>>();
cell.SetContext(Context);
cell.SetVisible(false);
cell.DataIndex = -1;
return cell;
}
/// <summary>
/// Gets the circular index.
/// </summary>
/// <returns>The circular index.</returns>
/// <param name="index">Index.</param>
/// <param name="maxSize">Max size.</param>
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<TData> : FancyScrollView<TData, FancyScrollViewNullContext>
{
}
}