208 lines
6.3 KiB
C#
208 lines
6.3 KiB
C#
/// Credit setchi (https://github.com/setchi)
|
|
/// Sourced from - https://github.com/setchi/FancyScrollView
|
|
|
|
using System.Collections.Generic;
|
|
|
|
namespace UnityEngine.UI.Extensions
|
|
{
|
|
public 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;
|
|
|
|
float currentPosition;
|
|
readonly List<FancyScrollViewCell<TData, TContext>> cells =
|
|
new List<FancyScrollViewCell<TData, TContext>>();
|
|
|
|
protected TContext context;
|
|
protected List<TData> cellData = new List<TData>();
|
|
|
|
protected void Awake()
|
|
{
|
|
cellBase.SetActive(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// コンテキストを設定します
|
|
/// </summary>
|
|
/// <param name="context"></param>
|
|
protected void SetContext(TContext context)
|
|
{
|
|
this.context = context;
|
|
|
|
for (int i = 0; i < cells.Count; i++)
|
|
{
|
|
cells[i].SetContext(context);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// セルを生成して返します
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
FancyScrollViewCell<TData, TContext> CreateCell()
|
|
{
|
|
var cellObject = Instantiate(cellBase);
|
|
cellObject.SetActive(true);
|
|
var cell = cellObject.GetComponent<FancyScrollViewCell<TData, TContext>>();
|
|
|
|
var cellRectTransform = cell.transform as RectTransform;
|
|
|
|
// 親要素の付け替えをおこなうとスケールやサイズが失われるため、変数に保持しておく
|
|
var scale = cell.transform.localScale;
|
|
var sizeDelta = Vector2.zero;
|
|
var offsetMin = Vector2.zero;
|
|
var offsetMax = Vector2.zero;
|
|
|
|
if (cellRectTransform)
|
|
{
|
|
sizeDelta = cellRectTransform.sizeDelta;
|
|
offsetMin = cellRectTransform.offsetMin;
|
|
offsetMax = cellRectTransform.offsetMax;
|
|
}
|
|
|
|
cell.transform.SetParent(cellBase.transform.parent);
|
|
|
|
cell.transform.localScale = scale;
|
|
if (cellRectTransform)
|
|
{
|
|
cellRectTransform.sizeDelta = sizeDelta;
|
|
cellRectTransform.offsetMin = offsetMin;
|
|
cellRectTransform.offsetMax = offsetMax;
|
|
}
|
|
|
|
cell.SetContext(context);
|
|
cell.SetVisible(false);
|
|
|
|
return cell;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
float prevCellInterval, prevCellOffset;
|
|
bool prevLoop;
|
|
|
|
void LateUpdate()
|
|
{
|
|
if (prevLoop != loop ||
|
|
prevCellOffset != cellOffset ||
|
|
prevCellInterval != cellInterval)
|
|
{
|
|
UpdatePosition(currentPosition);
|
|
|
|
prevLoop = loop;
|
|
prevCellOffset = cellOffset;
|
|
prevCellInterval = cellInterval;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// セルの内容を更新します
|
|
/// </summary>
|
|
/// <param name="cell"></param>
|
|
/// <param name="dataIndex"></param>
|
|
void UpdateCellForIndex(FancyScrollViewCell<TData, TContext> cell, int dataIndex)
|
|
{
|
|
if (loop)
|
|
{
|
|
dataIndex = GetLoopIndex(dataIndex, cellData.Count);
|
|
}
|
|
else if (dataIndex < 0 || dataIndex > cellData.Count - 1)
|
|
{
|
|
// セルに対応するデータが存在しなければセルを表示しない
|
|
cell.SetVisible(false);
|
|
return;
|
|
}
|
|
|
|
cell.SetVisible(true);
|
|
cell.DataIndex = dataIndex;
|
|
cell.UpdateContent(cellData[dataIndex]);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 円環構造の index を取得します
|
|
/// </summary>
|
|
/// <param name="index"></param>
|
|
/// <param name="length"></param>
|
|
/// <returns></returns>
|
|
int GetLoopIndex(int index, int length)
|
|
{
|
|
if (index < 0)
|
|
{
|
|
index = (length - 1) + (index + 1) % length;
|
|
}
|
|
else if (index > length - 1)
|
|
{
|
|
index = index % length;
|
|
}
|
|
return index;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 表示内容を更新します
|
|
/// </summary>
|
|
protected void UpdateContents()
|
|
{
|
|
UpdatePosition(currentPosition);
|
|
}
|
|
|
|
/// <summary>
|
|
/// スクロール位置を更新します
|
|
/// </summary>
|
|
/// <param name="position"></param>
|
|
protected void UpdatePosition(float position)
|
|
{
|
|
currentPosition = position;
|
|
|
|
var visibleMinPosition = position - (cellOffset / cellInterval);
|
|
var firstCellPosition = (Mathf.Ceil(visibleMinPosition) - visibleMinPosition) * cellInterval;
|
|
var dataStartIndex = Mathf.CeilToInt(visibleMinPosition);
|
|
var count = 0;
|
|
var cellIndex = 0;
|
|
|
|
for (float pos = firstCellPosition; pos <= 1f; pos += cellInterval, count++)
|
|
{
|
|
if (count >= cells.Count)
|
|
{
|
|
cells.Add(CreateCell());
|
|
}
|
|
}
|
|
|
|
count = 0;
|
|
|
|
for (float pos = firstCellPosition; pos <= 1f; count++, pos += cellInterval)
|
|
{
|
|
var dataIndex = dataStartIndex + count;
|
|
cellIndex = GetLoopIndex(dataIndex, cells.Count);
|
|
if (cells[cellIndex].gameObject.activeSelf)
|
|
{
|
|
cells[cellIndex].UpdatePosition(pos);
|
|
}
|
|
UpdateCellForIndex(cells[cellIndex], dataIndex);
|
|
}
|
|
|
|
cellIndex = GetLoopIndex(dataStartIndex + count, cells.Count);
|
|
|
|
for (; count < cells.Count; count++, cellIndex = GetLoopIndex(dataStartIndex + count, cells.Count))
|
|
{
|
|
cells[cellIndex].SetVisible(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
public sealed class FancyScrollViewNullContext
|
|
{
|
|
|
|
}
|
|
|
|
public class FancyScrollView<TData> : FancyScrollView<TData, FancyScrollViewNullContext>
|
|
{
|
|
|
|
}
|
|
} |