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