Merged in dev/fancyscrollviewupdate (pull request #77)
Updated Fancy Scroll View code to the latest from repopull/413/head
commit
9a66b92de2
|
@ -1,16 +1,17 @@
|
||||||
/// Credit setchi (https://github.com/setchi)
|
/// Credit setchi (https://github.com/setchi)
|
||||||
/// Sourced from - https://github.com/setchi/FancyScrollView
|
/// Sourced from - https://github.com/setchi/FancyScrollView
|
||||||
|
|
||||||
|
|
||||||
namespace UnityEngine.UI.Extensions
|
namespace UnityEngine.UI.Extensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="FancyScrollView{TItemData, TContext}"/> のセルを実装するための抽象基底クラス.
|
/// <see cref="FancyScrollView{TItemData, TContext}"/> のセルを実装するための抽象基底クラス.
|
||||||
/// <see cref="FancyScrollViewCell{TItemData, TContext}.Context"/> が不要な場合は
|
/// <see cref="FancyCell{TItemData, TContext}.Context"/> が不要な場合は
|
||||||
/// 代わりに <see cref="FancyScrollViewCell{TItemData}"/> を使用します.
|
/// 代わりに <see cref="FancyCell{TItemData}"/> を使用します.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TItemData">アイテムのデータ型.</typeparam>
|
/// <typeparam name="TItemData">アイテムのデータ型.</typeparam>
|
||||||
/// <typeparam name="TContext"><see cref="Context"/> の型.</typeparam>
|
/// <typeparam name="TContext"><see cref="Context"/> の型.</typeparam>
|
||||||
public abstract class FancyScrollViewCell<TItemData, TContext> : MonoBehaviour where TContext : class, new()
|
public abstract class FancyCell<TItemData, TContext> : MonoBehaviour where TContext : class, new()
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// このセルで表示しているデータのインデックス.
|
/// このセルで表示しているデータのインデックス.
|
||||||
|
@ -29,10 +30,15 @@ namespace UnityEngine.UI.Extensions
|
||||||
protected TContext Context { get; private set; }
|
protected TContext Context { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="Context"/> のセットアップを行います.
|
/// <see cref="Context"/> をセットします.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">コンテキスト.</param>
|
/// <param name="context">コンテキスト.</param>
|
||||||
public virtual void SetupContext(TContext context) => Context = context;
|
public virtual void SetContext(TContext context) => Context = context;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初期化を行います.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void Initialize() { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// このセルの可視状態を設定します.
|
/// このセルの可視状態を設定します.
|
||||||
|
@ -57,10 +63,10 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// <see cref="FancyScrollView{TItemData}"/> のセルを実装するための抽象基底クラス.
|
/// <see cref="FancyScrollView{TItemData}"/> のセルを実装するための抽象基底クラス.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TItemData">アイテムのデータ型.</typeparam>
|
/// <typeparam name="TItemData">アイテムのデータ型.</typeparam>
|
||||||
/// <seealso cref="FancyScrollViewCell{TItemData, TContext}"/>
|
/// <seealso cref="FancyCell{TItemData, TContext}"/>
|
||||||
public abstract class FancyScrollViewCell<TItemData> : FancyScrollViewCell<TItemData, FancyScrollViewNullContext>
|
public abstract class FancyCell<TItemData> : FancyCell<TItemData, NullContext>
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public sealed override void SetupContext(FancyScrollViewNullContext context) => base.SetupContext(context);
|
public sealed override void SetContext(NullContext context) => base.SetContext(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -42,8 +42,7 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SerializeField] protected Transform cellContainer = default;
|
[SerializeField] protected Transform cellContainer = default;
|
||||||
|
|
||||||
readonly IList<FancyScrollViewCell<TItemData, TContext>> pool =
|
readonly IList<FancyCell<TItemData, TContext>> pool = new List<FancyCell<TItemData, TContext>>();
|
||||||
new List<FancyScrollViewCell<TItemData, TContext>>();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初期化済みかどうか.
|
/// 初期化済みかどうか.
|
||||||
|
@ -90,7 +89,12 @@ namespace UnityEngine.UI.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// セルの表示内容を更新します.
|
/// セルのレイアウトを強制的に更新します.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void Relayout() => UpdatePosition(currentPosition, false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// セルのレイアウトと表示内容を強制的に更新します.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void Refresh() => UpdatePosition(currentPosition, true);
|
protected virtual void Refresh() => UpdatePosition(currentPosition, true);
|
||||||
|
|
||||||
|
@ -130,16 +134,16 @@ namespace UnityEngine.UI.Extensions
|
||||||
var addCount = Mathf.CeilToInt((1f - firstPosition) / cellInterval) - pool.Count;
|
var addCount = Mathf.CeilToInt((1f - firstPosition) / cellInterval) - pool.Count;
|
||||||
for (var i = 0; i < addCount; i++)
|
for (var i = 0; i < addCount; i++)
|
||||||
{
|
{
|
||||||
var cell = Instantiate(CellPrefab, cellContainer)
|
var cell = Instantiate(CellPrefab, cellContainer).GetComponent<FancyCell<TItemData, TContext>>();
|
||||||
.GetComponent<FancyScrollViewCell<TItemData, TContext>>();
|
|
||||||
if (cell == null)
|
if (cell == null)
|
||||||
{
|
{
|
||||||
throw new MissingComponentException(
|
throw new MissingComponentException(string.Format(
|
||||||
$"FancyScrollViewCell<{typeof(TItemData).FullName}, {typeof(TContext).FullName}> " +
|
"FancyCell<{0}, {1}> component not found in {2}.",
|
||||||
$"component not found in {CellPrefab.name}.");
|
typeof(TItemData).FullName, typeof(TContext).FullName, CellPrefab.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
cell.SetupContext(Context);
|
cell.SetContext(Context);
|
||||||
|
cell.Initialize();
|
||||||
cell.SetVisible(false);
|
cell.SetVisible(false);
|
||||||
pool.Add(cell);
|
pool.Add(cell);
|
||||||
}
|
}
|
||||||
|
@ -200,7 +204,7 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="FancyScrollView{TItemData}"/> のコンテキストクラス.
|
/// <see cref="FancyScrollView{TItemData}"/> のコンテキストクラス.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class FancyScrollViewNullContext { }
|
public sealed class NullContext { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// スクロールビューを実装するための抽象基底クラス.
|
/// スクロールビューを実装するための抽象基底クラス.
|
||||||
|
@ -208,5 +212,5 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TItemData"></typeparam>
|
/// <typeparam name="TItemData"></typeparam>
|
||||||
/// <seealso cref="FancyScrollView{TItemData, TContext}"/>
|
/// <seealso cref="FancyScrollView{TItemData, TContext}"/>
|
||||||
public abstract class FancyScrollView<TItemData> : FancyScrollView<TItemData, FancyScrollViewNullContext> { }
|
public abstract class FancyScrollView<TItemData> : FancyScrollView<TItemData, NullContext> { }
|
||||||
}
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/// Credit setchi (https://github.com/setchi)
|
||||||
|
/// Sourced from - https://github.com/setchi/FancyScrollView
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace UnityEngine.UI.Extensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 複数の <see cref="FancyCell{TItemData, TContext}"/> を持つセルグループ実装するための抽象基底クラス.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TItemData">アイテムのデータ型.</typeparam>
|
||||||
|
/// <typeparam name="TContext"><see cref="FancyCell{TItemData, TContext}.Context"/> の型.</typeparam>
|
||||||
|
public abstract class FancyCellGroup<TItemData, TContext> : FancyCell<TItemData[], TContext>
|
||||||
|
where TContext : class, IFancyCellGroupContext, new()
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// このグループで表示するセルの配列.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual FancyCell<TItemData, TContext>[] Cells { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// このグループで表示するセルの配列をインスタンス化します.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>このグループで表示するセルの配列.</returns>
|
||||||
|
protected virtual FancyCell<TItemData, TContext>[] InstantiateCells()
|
||||||
|
{
|
||||||
|
return Enumerable.Range(0, Context.GetGroupCount())
|
||||||
|
.Select(_ => Instantiate(Context.CellTemplate, transform))
|
||||||
|
.Select(x => x.GetComponent<FancyCell<TItemData, TContext>>())
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
Cells = InstantiateCells();
|
||||||
|
Debug.Assert(Cells.Length == Context.GetGroupCount());
|
||||||
|
|
||||||
|
for (var i = 0; i < Cells.Length; i++)
|
||||||
|
{
|
||||||
|
Cells[i].SetContext(Context);
|
||||||
|
Cells[i].Initialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override void UpdateContent(TItemData[] contents)
|
||||||
|
{
|
||||||
|
var firstCellIndex = Index * Context.GetGroupCount();
|
||||||
|
|
||||||
|
for (var i = 0; i < Cells.Length; i++)
|
||||||
|
{
|
||||||
|
Cells[i].Index = i + firstCellIndex;
|
||||||
|
Cells[i].SetVisible(i < contents.Length);
|
||||||
|
|
||||||
|
if (Cells[i].IsVisible)
|
||||||
|
{
|
||||||
|
Cells[i].UpdateContent(contents[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override void UpdatePosition(float position)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < Cells.Length; i++)
|
||||||
|
{
|
||||||
|
Cells[i].UpdatePosition(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 3e786463ba934403cacf7e8c0d5822d7
|
guid: 5d97e25c7748b8d44acd2298e509c8f1
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
|
@ -11,77 +11,106 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// グリッドレイアウトのスクロールビューを実装するための抽象基底クラス.
|
/// グリッドレイアウトのスクロールビューを実装するための抽象基底クラス.
|
||||||
/// 無限スクロールおよびスナップには対応していません.
|
/// 無限スクロールおよびスナップには対応していません.
|
||||||
|
/// <see cref="FancyScrollView{TItemData, TContext}.Context"/> が不要な場合は
|
||||||
|
/// 代わりに <see cref="FancyGridView{TItemData}"/> を使用します.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TItemData">アイテムのデータ型.</typeparam>
|
/// <typeparam name="TItemData">アイテムのデータ型.</typeparam>
|
||||||
/// <typeparam name="TContext"><see cref="FancyScrollView{TItemData, TContext}.Context"/> の型.</typeparam>
|
/// <typeparam name="TContext"><see cref="FancyScrollView{TItemData, TContext}.Context"/> の型.</typeparam>
|
||||||
public abstract class FancyGridView<TItemData, TContext> : FancyScrollRect<TItemData[], TContext>
|
public abstract class FancyGridView<TItemData, TContext> : FancyScrollRect<TItemData[], TContext>
|
||||||
where TContext : class, IFancyScrollRectContext, IFancyGridViewContext, new()
|
where TContext : class, IFancyGridViewContext, new()
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// カラム同士の余白.
|
/// デフォルトのセルグループクラス.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SerializeField] protected float columnSpacing = 0f;
|
protected abstract class DefaultCellGroup : FancyCellGroup<TItemData, TContext> { }
|
||||||
|
|
||||||
GameObject cachedRowPrefab;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 行の Prefab.
|
/// 最初にセルを配置する軸方向のセル同士の余白.
|
||||||
|
/// </summary>
|
||||||
|
[SerializeField] protected float startAxisSpacing = 0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 最初にセルを配置する軸方向のセル数.
|
||||||
|
/// </summary>
|
||||||
|
[SerializeField] protected int startAxisCellCount = 4;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// セルのサイズ.
|
||||||
|
/// </summary>
|
||||||
|
[SerializeField] protected Vector2 cellSize = new Vector2(100f, 100f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// セルのグループ Prefab.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// <see cref="FancyGridView{TItemData, TContext}"/> では,
|
/// <see cref="FancyGridView{TItemData, TContext}"/> では,
|
||||||
/// <see cref="FancyScrollView{TItemData, TContext}.CellPrefab"/> を行オブジェクトとして使用します.
|
/// <see cref="FancyScrollView{TItemData, TContext}.CellPrefab"/> を最初にセルを配置する軸方向のセルコンテナとして使用します.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
protected sealed override GameObject CellPrefab => cachedRowPrefab ?? (cachedRowPrefab = SetupRowTemplate());
|
protected sealed override GameObject CellPrefab => cellGroupTemplate;
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc/>
|
||||||
/// 一行あたりの要素数.
|
protected override float CellSize => Scroller.ScrollDirection == ScrollDirection.Horizontal
|
||||||
/// </summary>
|
? cellSize.x
|
||||||
protected abstract int ColumnCount { get; }
|
: cellSize.y;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// セルのテンプレート.
|
|
||||||
/// </summary>
|
|
||||||
protected abstract FancyScrollViewCell<TItemData, TContext> CellTemplate { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 行オブジェクトのテンプレート.
|
|
||||||
/// </summary>
|
|
||||||
protected abstract FancyGridViewRow<TItemData, TContext> RowTemplate { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// アイテムの総数.
|
/// アイテムの総数.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int DataCount { get; private set; }
|
public int DataCount { get; private set; }
|
||||||
|
|
||||||
|
GameObject cellGroupTemplate;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override void Initialize()
|
protected override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
Debug.Assert(RowTemplate != null);
|
Debug.Assert(startAxisCellCount > 0);
|
||||||
Debug.Assert(CellTemplate != null);
|
|
||||||
Debug.Assert(ColumnCount > 0);
|
|
||||||
|
|
||||||
Context.CellTemplate = CellTemplate.gameObject;
|
|
||||||
Context.ScrollDirection = Scroller.ScrollDirection;
|
Context.ScrollDirection = Scroller.ScrollDirection;
|
||||||
Context.GetColumnCount = () => ColumnCount;
|
Context.GetGroupCount = () => startAxisCellCount;
|
||||||
Context.GetColumnSpacing = () => columnSpacing;
|
Context.GetStartAxisSpacing = () => startAxisSpacing;
|
||||||
|
Context.GetCellSize = () => Scroller.ScrollDirection == ScrollDirection.Horizontal
|
||||||
|
? cellSize.y
|
||||||
|
: cellSize.x;
|
||||||
|
|
||||||
|
SetupCellTemplate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 行オブジェクトのセットアップを行います.
|
/// 最初にセルが生成される直前に呼び出されます.
|
||||||
|
/// <see cref="Setup{TGroup}(FancyCell{TItemData, TContext})"/> メソッドを使用してセルテンプレートのセットアップを行ってください.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>行を構成する <c>GameObject</c>.</returns>
|
/// <example>
|
||||||
protected virtual GameObject SetupRowTemplate()
|
/// <code><![CDATA[
|
||||||
|
/// using UnityEngine;
|
||||||
|
/// using FancyScrollView;
|
||||||
|
///
|
||||||
|
/// public class MyGridView : FancyGridView<ItemData, Context>
|
||||||
|
/// {
|
||||||
|
/// class CellGroup : DefaultCellGroup { }
|
||||||
|
///
|
||||||
|
/// [SerializeField] Cell cellPrefab = default;
|
||||||
|
///
|
||||||
|
/// protected override void SetupCellTemplate() => Setup<CellGroup>(cellPrefab);
|
||||||
|
/// }
|
||||||
|
/// ]]></code>
|
||||||
|
/// </example>
|
||||||
|
protected abstract void SetupCellTemplate();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// セルテンプレートのセットアップを行います.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cellTemplate">セルのテンプレート.</param>
|
||||||
|
/// <typeparam name="TGroup">セルグループの型.</typeparam>
|
||||||
|
protected virtual void Setup<TGroup>(FancyCell<TItemData, TContext> cellTemplate)
|
||||||
|
where TGroup : FancyCell<TItemData[], TContext>
|
||||||
{
|
{
|
||||||
var cell = CellTemplate.GetComponent<RectTransform>();
|
Context.CellTemplate = cellTemplate.gameObject;
|
||||||
var row = RowTemplate.GetComponent<RectTransform>();
|
|
||||||
|
|
||||||
row.sizeDelta = Scroller.ScrollDirection == ScrollDirection.Horizontal
|
cellGroupTemplate = new GameObject("Group").AddComponent<TGroup>().gameObject;
|
||||||
? new Vector2(cell.rect.width, row.sizeDelta.y)
|
cellGroupTemplate.transform.SetParent(cellContainer, false);
|
||||||
: new Vector2(row.sizeDelta.x, cell.rect.height);
|
cellGroupTemplate.SetActive(false);
|
||||||
|
|
||||||
return row.gameObject;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -92,15 +121,26 @@ namespace UnityEngine.UI.Extensions
|
||||||
{
|
{
|
||||||
DataCount = items.Count;
|
DataCount = items.Count;
|
||||||
|
|
||||||
var rows = items
|
var itemGroups = items
|
||||||
.Select((item, index) => (item, index))
|
.Select((item, index) => (item, index))
|
||||||
.GroupBy(
|
.GroupBy(
|
||||||
x => x.index / ColumnCount,
|
x => x.index / startAxisCellCount,
|
||||||
x => x.item)
|
x => x.item)
|
||||||
.Select(group => group.ToArray())
|
.Select(group => group.ToArray())
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
UpdateContents(rows);
|
UpdateContents(itemGroups);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 指定したアイテムの位置までジャンプします.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="itemIndex">アイテムのインデックス.</param>
|
||||||
|
/// <param name="alignment">ビューポート内におけるセル位置の基準. 0f(先頭) ~ 1f(末尾).</param>
|
||||||
|
protected override void JumpTo(int itemIndex, float alignment = 0.5f)
|
||||||
|
{
|
||||||
|
var groupIndex = itemIndex / startAxisCellCount;
|
||||||
|
base.JumpTo(groupIndex, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -108,12 +148,12 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="itemIndex">アイテムのインデックス.</param>
|
/// <param name="itemIndex">アイテムのインデックス.</param>
|
||||||
/// <param name="duration">移動にかける秒数.</param>
|
/// <param name="duration">移動にかける秒数.</param>
|
||||||
/// <param name="alignment"><see cref="Alignment"/>.</param>
|
/// <param name="alignment">ビューポート内におけるセル位置の基準. 0f(先頭) ~ 1f(末尾).</param>
|
||||||
/// <param name="onComplete">移動が完了した際に呼び出されるコールバック.</param>
|
/// <param name="onComplete">移動が完了した際に呼び出されるコールバック.</param>
|
||||||
public override void ScrollTo(int itemIndex, float duration, Alignment alignment = Alignment.Center, Action onComplete = null)
|
protected override void ScrollTo(int itemIndex, float duration, float alignment = 0.5f, Action onComplete = null)
|
||||||
{
|
{
|
||||||
var rowIndex = itemIndex / Context.GetColumnCount();
|
var groupIndex = itemIndex / startAxisCellCount;
|
||||||
base.ScrollTo(rowIndex, duration, alignment, onComplete);
|
base.ScrollTo(groupIndex, duration, alignment, onComplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -122,23 +162,20 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// <param name="itemIndex">アイテムのインデックス.</param>
|
/// <param name="itemIndex">アイテムのインデックス.</param>
|
||||||
/// <param name="duration">移動にかける秒数.</param>
|
/// <param name="duration">移動にかける秒数.</param>
|
||||||
/// <param name="easing">移動に使用するイージング.</param>
|
/// <param name="easing">移動に使用するイージング.</param>
|
||||||
/// <param name="alignment"><see cref="Alignment"/>.</param>
|
/// <param name="alignment">ビューポート内におけるセル位置の基準. 0f(先頭) ~ 1f(末尾).</param>
|
||||||
/// <param name="onComplete">移動が完了した際に呼び出されるコールバック.</param>
|
/// <param name="onComplete">移動が完了した際に呼び出されるコールバック.</param>
|
||||||
public override void ScrollTo(int itemIndex, float duration, Ease easing, Alignment alignment = Alignment.Center, Action onComplete = null)
|
protected override void ScrollTo(int itemIndex, float duration, Ease easing, float alignment = 0.5f, Action onComplete = null)
|
||||||
{
|
{
|
||||||
var rowIndex = itemIndex / Context.GetColumnCount();
|
var groupIndex = itemIndex / startAxisCellCount;
|
||||||
base.ScrollTo(rowIndex, duration, easing, alignment, onComplete);
|
base.ScrollTo(groupIndex, duration, easing, alignment, onComplete);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 指定したアイテムの位置までジャンプします.
|
/// グリッドレイアウトのスクロールビューを実装するための抽象基底クラス.
|
||||||
|
/// 無限スクロールおよびスナップには対応していません.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="itemIndex">アイテムのインデックス.</param>
|
/// <typeparam name="TItemData">アイテムのデータ型.</typeparam>
|
||||||
/// <param name="alignment"><see cref="Alignment"/>.</param>
|
/// <seealso cref="FancyGridView{TItemData, TContext}"/>
|
||||||
public virtual void JumpTo(int itemIndex, Alignment alignment = Alignment.Center)
|
public abstract class FancyGridView<TItemData> : FancyGridView<TItemData, FancyGridViewContext> { }
|
||||||
{
|
|
||||||
var rowIndex = itemIndex / Context.GetColumnCount();
|
|
||||||
UpdatePosition(rowIndex, alignment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/// Credit setchi (https://github.com/setchi)
|
||||||
|
/// Sourced from - https://github.com/setchi/FancyScrollView
|
||||||
|
|
||||||
|
namespace UnityEngine.UI.Extensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="FancyGridView{TItemData, TContext}"/> のセルを実装するための抽象基底クラス.
|
||||||
|
/// <see cref="FancyCell{TItemData, TContext}.Context"/> が不要な場合は
|
||||||
|
/// 代わりに <see cref="FancyGridViewCell{TItemData}"/> を使用します.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TItemData">アイテムのデータ型.</typeparam>
|
||||||
|
/// <typeparam name="TContext"><see cref="FancyCell{TItemData, TContext}.Context"/> の型.</typeparam>
|
||||||
|
public abstract class FancyGridViewCell<TItemData, TContext> : FancyScrollRectCell<TItemData, TContext>
|
||||||
|
where TContext : class, IFancyGridViewContext, new()
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected override void UpdatePosition(float normalizedPosition, float localPosition)
|
||||||
|
{
|
||||||
|
var cellSize = Context.GetCellSize();
|
||||||
|
var spacing = Context.GetStartAxisSpacing();
|
||||||
|
var groupCount = Context.GetGroupCount();
|
||||||
|
|
||||||
|
var indexInGroup = Index % groupCount;
|
||||||
|
var positionInGroup = (cellSize + spacing) * (indexInGroup - (groupCount - 1) * 0.5f);
|
||||||
|
|
||||||
|
transform.localPosition = Context.ScrollDirection == ScrollDirection.Horizontal
|
||||||
|
? new Vector2(-localPosition, -positionInGroup)
|
||||||
|
: new Vector2(positionInGroup, localPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="FancyGridView{TItemData}"/> のセルを実装するための抽象基底クラス.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TItemData">アイテムのデータ型.</typeparam>
|
||||||
|
/// <seealso cref="FancyGridViewCell{TItemData, TContext}"/>
|
||||||
|
public abstract class FancyGridViewCell<TItemData> : FancyGridViewCell<TItemData, FancyGridViewContext>
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public sealed override void SetContext(FancyGridViewContext context) => base.SetContext(context);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 84300901ad8704c11b39587ed6d87468
|
guid: ab8a59bbf5118824ab084e32342ad86b
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
|
@ -8,16 +8,13 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="FancyGridView{TItemData, TContext}"/> のコンテキスト基底クラス.
|
/// <see cref="FancyGridView{TItemData, TContext}"/> のコンテキスト基底クラス.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class FancyGridViewContext : IFancyGridViewContext, IFancyScrollRectContext
|
public class FancyGridViewContext : IFancyGridViewContext
|
||||||
{
|
{
|
||||||
|
ScrollDirection IFancyScrollRectContext.ScrollDirection { get; set; }
|
||||||
Func<(float ScrollSize, float ReuseMargin)> IFancyScrollRectContext.CalculateScrollSize { get; set; }
|
Func<(float ScrollSize, float ReuseMargin)> IFancyScrollRectContext.CalculateScrollSize { get; set; }
|
||||||
|
GameObject IFancyCellGroupContext.CellTemplate { get; set; }
|
||||||
GameObject IFancyGridViewContext.CellTemplate { get; set; }
|
Func<int> IFancyCellGroupContext.GetGroupCount { get; set; }
|
||||||
|
Func<float> IFancyGridViewContext.GetStartAxisSpacing { get; set; }
|
||||||
ScrollDirection IFancyGridViewContext.ScrollDirection { get; set; }
|
Func<float> IFancyGridViewContext.GetCellSize { get; set; }
|
||||||
|
|
||||||
public Func<int> GetColumnCount { get; set; }
|
|
||||||
|
|
||||||
public Func<float> GetColumnSpacing { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,81 +0,0 @@
|
||||||
/// Credit setchi (https://github.com/setchi)
|
|
||||||
/// Sourced from - https://github.com/setchi/FancyScrollView
|
|
||||||
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace UnityEngine.UI.Extensions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// <see cref="FancyGridView{TItemData, TContext}"/> の行を実装するための抽象基底クラス.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TItemData">アイテムのデータ型.</typeparam>
|
|
||||||
/// <typeparam name="TContext"><see cref="FancyScrollViewCell{TItemData, TContext}.Context"/> の型.</typeparam>
|
|
||||||
public abstract class FancyGridViewRow<TItemData, TContext> : FancyScrollRectCell<TItemData[], TContext>
|
|
||||||
where TContext : class, IFancyScrollRectContext, IFancyGridViewContext, new()
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// この行で表示するセルの配列.
|
|
||||||
/// </summary>
|
|
||||||
protected virtual FancyScrollViewCell<TItemData, TContext>[] Cells { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// この行で表示するセルの配列をインスタンス化します.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>この行で表示するセルの配列.</returns>
|
|
||||||
protected virtual FancyScrollViewCell<TItemData, TContext>[] InstantiateCells()
|
|
||||||
{
|
|
||||||
return Enumerable.Range(0, Context.GetColumnCount())
|
|
||||||
.Select(_ => Instantiate(Context.CellTemplate, transform))
|
|
||||||
.Select(x => x.GetComponent<FancyScrollViewCell<TItemData, TContext>>())
|
|
||||||
.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override void SetupContext(TContext context)
|
|
||||||
{
|
|
||||||
base.SetupContext(context);
|
|
||||||
|
|
||||||
Cells = InstantiateCells();
|
|
||||||
Debug.Assert(Cells.Length == Context.GetColumnCount());
|
|
||||||
|
|
||||||
for (var i = 0; i < Cells.Length; i++)
|
|
||||||
{
|
|
||||||
Cells[i].SetupContext(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override void UpdateContent(TItemData[] rowContents)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < Cells.Length; i++)
|
|
||||||
{
|
|
||||||
Cells[i].Index = i + Index * Context.GetColumnCount();
|
|
||||||
Cells[i].SetVisible(i < rowContents.Length);
|
|
||||||
|
|
||||||
if (Cells[i].IsVisible)
|
|
||||||
{
|
|
||||||
Cells[i].UpdateContent(rowContents[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override void UpdatePosition(float position)
|
|
||||||
{
|
|
||||||
base.UpdatePosition(position);
|
|
||||||
|
|
||||||
for (var i = 0; i < Cells.Length; i++)
|
|
||||||
{
|
|
||||||
Cells[i].UpdatePosition(position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override void UpdatePosition(float position, float viewportPosition)
|
|
||||||
{
|
|
||||||
transform.localPosition = Context.ScrollDirection == ScrollDirection.Horizontal
|
|
||||||
? new Vector2(viewportPosition, transform.localPosition.y)
|
|
||||||
: new Vector2(transform.localPosition.x, viewportPosition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
/// Credit setchi (https://github.com/setchi)
|
||||||
|
/// Sourced from - https://github.com/setchi/FancyScrollView
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace UnityEngine.UI.Extensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="FancyCellGroup{TItemData, TContext}"/> のコンテキストインターフェース.
|
||||||
|
/// </summary>
|
||||||
|
public interface IFancyCellGroupContext
|
||||||
|
{
|
||||||
|
GameObject CellTemplate { get; set; }
|
||||||
|
Func<int> GetGroupCount { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 1dc086f250206754aa8449e252d50388
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -8,11 +8,9 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="FancyGridView{TItemData, TContext}"/> のコンテキストインターフェース.
|
/// <see cref="FancyGridView{TItemData, TContext}"/> のコンテキストインターフェース.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IFancyGridViewContext
|
public interface IFancyGridViewContext : IFancyScrollRectContext, IFancyCellGroupContext
|
||||||
{
|
{
|
||||||
GameObject CellTemplate { get; set; }
|
Func<float> GetStartAxisSpacing { get; set; }
|
||||||
ScrollDirection ScrollDirection { get; set; }
|
Func<float> GetCellSize { get; set ; }
|
||||||
Func<int> GetColumnCount { get; set; }
|
|
||||||
Func<float> GetColumnSpacing { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,12 +0,0 @@
|
||||||
/// Credit setchi (https://github.com/setchi)
|
|
||||||
/// Sourced from - https://github.com/setchi/FancyScrollView
|
|
||||||
|
|
||||||
namespace UnityEngine.UI.Extensions
|
|
||||||
{
|
|
||||||
public enum Alignment
|
|
||||||
{
|
|
||||||
Head,
|
|
||||||
Center,
|
|
||||||
Tail,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -39,10 +39,15 @@ namespace UnityEngine.UI.Extensions
|
||||||
[SerializeField] protected float paddingTail = 0f;
|
[SerializeField] protected float paddingTail = 0f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// セル同士の余白.
|
/// スクロール軸方向のセル同士の余白.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SerializeField] protected float spacing = 0f;
|
[SerializeField] protected float spacing = 0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// セルのサイズ.
|
||||||
|
/// </summary>
|
||||||
|
protected abstract float CellSize { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// スクロール可能かどうか.
|
/// スクロール可能かどうか.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -51,13 +56,6 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
protected virtual bool Scrollable => MaxScrollPosition > 0f;
|
protected virtual bool Scrollable => MaxScrollPosition > 0f;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// セルのサイズ.
|
|
||||||
/// </summary>
|
|
||||||
protected virtual float CellSize => Scroller.ScrollDirection == ScrollDirection.Horizontal
|
|
||||||
? CellRectTransform.rect.width
|
|
||||||
: CellRectTransform.rect.height;
|
|
||||||
|
|
||||||
Scroller cachedScroller;
|
Scroller cachedScroller;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -68,9 +66,6 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
protected Scroller Scroller => cachedScroller ?? (cachedScroller = GetComponent<Scroller>());
|
protected Scroller Scroller => cachedScroller ?? (cachedScroller = GetComponent<Scroller>());
|
||||||
|
|
||||||
RectTransform cachedCellRect;
|
|
||||||
RectTransform CellRectTransform => cachedCellRect ?? (cachedCellRect = CellPrefab.transform as RectTransform);
|
|
||||||
|
|
||||||
float ScrollLength => 1f / Mathf.Max(cellInterval, 1e-2f) - 1f;
|
float ScrollLength => 1f / Mathf.Max(cellInterval, 1e-2f) - 1f;
|
||||||
|
|
||||||
float ViewportLength => ScrollLength - reuseCellMarginCount * 2f;
|
float ViewportLength => ScrollLength - reuseCellMarginCount * 2f;
|
||||||
|
@ -87,6 +82,7 @@ namespace UnityEngine.UI.Extensions
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
|
Context.ScrollDirection = Scroller.ScrollDirection;
|
||||||
Context.CalculateScrollSize = () =>
|
Context.CalculateScrollSize = () =>
|
||||||
{
|
{
|
||||||
var interval = CellSize + spacing;
|
var interval = CellSize + spacing;
|
||||||
|
@ -138,6 +134,14 @@ namespace UnityEngine.UI.Extensions
|
||||||
base.Refresh();
|
base.Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected override void Relayout()
|
||||||
|
{
|
||||||
|
AdjustCellIntervalAndScrollOffset();
|
||||||
|
RefreshScroller();
|
||||||
|
base.Relayout();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="Scroller"/> の各種状態を更新します.
|
/// <see cref="Scroller"/> の各種状態を更新します.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -172,17 +176,17 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// <param name="position">スクロール位置.</param>
|
/// <param name="position">スクロール位置.</param>
|
||||||
protected new void UpdatePosition(float position)
|
protected new void UpdatePosition(float position)
|
||||||
{
|
{
|
||||||
UpdatePosition(position, Alignment.Center);
|
Scroller.Position = ToScrollerPosition(position, 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// スクロール位置を更新します.
|
/// 指定したアイテムの位置までジャンプします.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="position">スクロール位置.</param>
|
/// <param name="itemIndex">アイテムのインデックス.</param>
|
||||||
/// <param name="alignment"><see cref="Alignment"/>.</param>
|
/// <param name="alignment">ビューポート内におけるセル位置の基準. 0f(先頭) ~ 1f(末尾).</param>
|
||||||
protected virtual void UpdatePosition(float position, Alignment alignment)
|
protected virtual void JumpTo(int itemIndex, float alignment = 0.5f)
|
||||||
{
|
{
|
||||||
Scroller.Position = ToScrollerPosition(position, alignment);
|
Scroller.Position = ToScrollerPosition(itemIndex, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -190,9 +194,9 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="index">アイテムのインデックス.</param>
|
/// <param name="index">アイテムのインデックス.</param>
|
||||||
/// <param name="duration">移動にかける秒数.</param>
|
/// <param name="duration">移動にかける秒数.</param>
|
||||||
/// <param name="alignment"><see cref="Alignment"/>.</param>
|
/// <param name="alignment">ビューポート内におけるセル位置の基準. 0f(先頭) ~ 1f(末尾).</param>
|
||||||
/// <param name="onComplete">移動が完了した際に呼び出されるコールバック.</param>
|
/// <param name="onComplete">移動が完了した際に呼び出されるコールバック.</param>
|
||||||
public virtual void ScrollTo(int index, float duration, Alignment alignment = Alignment.Center, Action onComplete = null)
|
protected virtual void ScrollTo(int index, float duration, float alignment = 0.5f, Action onComplete = null)
|
||||||
{
|
{
|
||||||
Scroller.ScrollTo(ToScrollerPosition(index, alignment), duration, onComplete);
|
Scroller.ScrollTo(ToScrollerPosition(index, alignment), duration, onComplete);
|
||||||
}
|
}
|
||||||
|
@ -203,9 +207,9 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// <param name="index">アイテムのインデックス.</param>
|
/// <param name="index">アイテムのインデックス.</param>
|
||||||
/// <param name="duration">移動にかける秒数.</param>
|
/// <param name="duration">移動にかける秒数.</param>
|
||||||
/// <param name="easing">移動に使用するイージング.</param>
|
/// <param name="easing">移動に使用するイージング.</param>
|
||||||
/// <param name="alignment"><see cref="Alignment"/>.</param>
|
/// <param name="alignment">ビューポート内におけるセル位置の基準. 0f(先頭) ~ 1f(末尾).</param>
|
||||||
/// <param name="onComplete">移動が完了した際に呼び出されるコールバック.</param>
|
/// <param name="onComplete">移動が完了した際に呼び出されるコールバック.</param>
|
||||||
public virtual void ScrollTo(int index, float duration, Ease easing, Alignment alignment = Alignment.Center, Action onComplete = null)
|
protected virtual void ScrollTo(int index, float duration, Ease easing, float alignment = 0.5f, Action onComplete = null)
|
||||||
{
|
{
|
||||||
Scroller.ScrollTo(ToScrollerPosition(index, alignment), duration, easing, onComplete);
|
Scroller.ScrollTo(ToScrollerPosition(index, alignment), duration, easing, onComplete);
|
||||||
}
|
}
|
||||||
|
@ -244,25 +248,15 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// <see cref="FancyScrollRect{TItemData, TContext}"/> が扱うスクロール位置を <see cref="Scroller"/> が扱うスクロール位置に変換します.
|
/// <see cref="FancyScrollRect{TItemData, TContext}"/> が扱うスクロール位置を <see cref="Scroller"/> が扱うスクロール位置に変換します.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="position"><see cref="FancyScrollRect{TItemData, TContext}"/> が扱うスクロール位置.</param>
|
/// <param name="position"><see cref="FancyScrollRect{TItemData, TContext}"/> が扱うスクロール位置.</param>
|
||||||
/// <param name="alignment"><see cref="Alignment"/>.</param>
|
/// <param name="alignment">ビューポート内におけるセル位置の基準. 0f(先頭) ~ 1f(末尾).</param>
|
||||||
/// <returns><see cref="Scroller"/> が扱うスクロール位置.</returns>
|
/// <returns><see cref="Scroller"/> が扱うスクロール位置.</returns>
|
||||||
protected float ToScrollerPosition(float position, Alignment alignment = Alignment.Center)
|
protected float ToScrollerPosition(float position, float alignment = 0.5f)
|
||||||
{
|
{
|
||||||
var offset = (ScrollLength - (1f + reuseCellMarginCount * 2f)) * GetAnchore(alignment);
|
var offset = alignment * (ScrollLength - (1f + reuseCellMarginCount * 2f))
|
||||||
|
+ (1f - alignment - 0.5f) * spacing / (CellSize + spacing);
|
||||||
return ToScrollerPosition(Mathf.Clamp(position - offset, 0f, MaxScrollPosition));
|
return ToScrollerPosition(Mathf.Clamp(position - offset, 0f, MaxScrollPosition));
|
||||||
}
|
}
|
||||||
|
|
||||||
float GetAnchore(Alignment alignment)
|
|
||||||
{
|
|
||||||
switch (alignment)
|
|
||||||
{
|
|
||||||
case Alignment.Head: return 0.0f;
|
|
||||||
case Alignment.Center: return 0.5f;
|
|
||||||
case Alignment.Tail: return 1.0f;
|
|
||||||
default: return GetAnchore(Alignment.Center);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 指定された設定を実現するための
|
/// 指定された設定を実現するための
|
||||||
/// <see cref="FancyScrollView{TItemData,TContext}.cellInterval"/> と
|
/// <see cref="FancyScrollView{TItemData,TContext}.cellInterval"/> と
|
||||||
|
@ -276,11 +270,8 @@ namespace UnityEngine.UI.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnValidate()
|
protected virtual void OnValidate()
|
||||||
{
|
|
||||||
if (CellPrefab)
|
|
||||||
{
|
{
|
||||||
AdjustCellIntervalAndScrollOffset();
|
AdjustCellIntervalAndScrollOffset();
|
||||||
}
|
|
||||||
|
|
||||||
if (loop)
|
if (loop)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,12 +5,12 @@ namespace UnityEngine.UI.Extensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="FancyScrollRect{TItemData, TContext}"/> のセルを実装するための抽象基底クラス.
|
/// <see cref="FancyScrollRect{TItemData, TContext}"/> のセルを実装するための抽象基底クラス.
|
||||||
/// <see cref="FancyScrollViewCell{TItemData, TContext}.Context"/> が不要な場合は
|
/// <see cref="FancyCell{TItemData, TContext}.Context"/> が不要な場合は
|
||||||
/// 代わりに <see cref="FancyScrollRectCell{TItemData}"/> を使用します.
|
/// 代わりに <see cref="FancyScrollRectCell{TItemData}"/> を使用します.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TItemData">アイテムのデータ型.</typeparam>
|
/// <typeparam name="TItemData">アイテムのデータ型.</typeparam>
|
||||||
/// <typeparam name="TContext"><see cref="FancyScrollViewCell{TItemData, TContext}.Context"/> の型.</typeparam>
|
/// <typeparam name="TContext"><see cref="FancyCell{TItemData, TContext}.Context"/> の型.</typeparam>
|
||||||
public abstract class FancyScrollRectCell<TItemData, TContext> : FancyScrollViewCell<TItemData, TContext>
|
public abstract class FancyScrollRectCell<TItemData, TContext> : FancyCell<TItemData, TContext>
|
||||||
where TContext : class, IFancyScrollRectContext, new()
|
where TContext : class, IFancyScrollRectContext, new()
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
@ -18,24 +18,29 @@ namespace UnityEngine.UI.Extensions
|
||||||
{
|
{
|
||||||
var (scrollSize, reuseMargin) = Context.CalculateScrollSize();
|
var (scrollSize, reuseMargin) = Context.CalculateScrollSize();
|
||||||
|
|
||||||
var unclampedPosition = (Mathf.Lerp(0f, scrollSize, position) - reuseMargin) / (scrollSize - reuseMargin * 2f);
|
var normalizedPosition = (Mathf.Lerp(0f, scrollSize, position) - reuseMargin) / (scrollSize - reuseMargin * 2f);
|
||||||
|
|
||||||
var start = 0.5f * scrollSize;
|
var start = 0.5f * scrollSize;
|
||||||
var end = -start;
|
var end = -start;
|
||||||
|
|
||||||
UpdatePosition(unclampedPosition, Mathf.Lerp(start, end, position));
|
UpdatePosition(normalizedPosition, Mathf.Lerp(start, end, position));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// このセルの位置を更新します.
|
/// このセルの位置を更新します.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="position">
|
/// <param name="normalizedPosition">
|
||||||
/// ビューポートの範囲で正規化されたスクロール位置.
|
/// ビューポートの範囲で正規化されたスクロール位置.
|
||||||
/// <see cref="FancyScrollRect{TItemData, TContext}.reuseCellMarginCount"/> の値に基づいて
|
/// <see cref="FancyScrollRect{TItemData, TContext}.reuseCellMarginCount"/> の値に基づいて
|
||||||
/// <c>0.0</c> ~ <c>1.0</c> の範囲を超えた値が渡されることがあります.
|
/// <c>0.0</c> ~ <c>1.0</c> の範囲を超えた値が渡されることがあります.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="viewportPosition">ローカル位置.</param>
|
/// <param name="localPosition">ローカル位置.</param>
|
||||||
protected virtual void UpdatePosition(float position, float viewportPosition) { }
|
protected virtual void UpdatePosition(float normalizedPosition, float localPosition)
|
||||||
|
{
|
||||||
|
transform.localPosition = Context.ScrollDirection == ScrollDirection.Horizontal
|
||||||
|
? new Vector2(-localPosition, 0)
|
||||||
|
: new Vector2(0, localPosition);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -46,6 +51,6 @@ namespace UnityEngine.UI.Extensions
|
||||||
public abstract class FancyScrollRectCell<TItemData> : FancyScrollRectCell<TItemData, FancyScrollRectContext>
|
public abstract class FancyScrollRectCell<TItemData> : FancyScrollRectCell<TItemData, FancyScrollRectContext>
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public sealed override void SetupContext(FancyScrollRectContext context) => base.SetupContext(context);
|
public sealed override void SetContext(FancyScrollRectContext context) => base.SetContext(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,6 +10,7 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class FancyScrollRectContext : IFancyScrollRectContext
|
public class FancyScrollRectContext : IFancyScrollRectContext
|
||||||
{
|
{
|
||||||
|
ScrollDirection IFancyScrollRectContext.ScrollDirection { get; set; }
|
||||||
Func<(float ScrollSize, float ReuseMargin)> IFancyScrollRectContext.CalculateScrollSize { get; set; }
|
Func<(float ScrollSize, float ReuseMargin)> IFancyScrollRectContext.CalculateScrollSize { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,6 +10,7 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IFancyScrollRectContext
|
public interface IFancyScrollRectContext
|
||||||
{
|
{
|
||||||
|
ScrollDirection ScrollDirection { get; set; }
|
||||||
Func<(float ScrollSize, float ReuseMargin)> CalculateScrollSize { get; set; }
|
Func<(float ScrollSize, float ReuseMargin)> CalculateScrollSize { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,30 +1,8 @@
|
||||||
//
|
/*
|
||||||
// EasingCore - https://github.com/setchi/EasingCore
|
* EasingCore (https://github.com/setchi/EasingCore)
|
||||||
//
|
* Copyright (c) 2020 setchi
|
||||||
// The MIT License (MIT)
|
* Licensed under MIT (https://github.com/setchi/EasingCore/blob/master/LICENSE)
|
||||||
//
|
*/
|
||||||
// Copyright (c) 2019 setchi
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace UnityEngine.UI.Extensions.EasingCore
|
namespace UnityEngine.UI.Extensions.EasingCore
|
||||||
{
|
{
|
||||||
|
@ -63,14 +41,16 @@ namespace UnityEngine.UI.Extensions.EasingCore
|
||||||
InOutSine,
|
InOutSine,
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class EasingFunction
|
public delegate float EasingFunction(float t);
|
||||||
|
|
||||||
|
public static class Easing
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the easing function
|
/// Gets the easing function
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">Ease type</param>
|
/// <param name="type">Ease type</param>
|
||||||
/// <returns>Easing function</returns>
|
/// <returns>Easing function</returns>
|
||||||
public static Func<float, float> Get(Ease type)
|
public static EasingFunction Get(Ease type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// スクロール位置の制御を行うコンポーネント.
|
/// スクロール位置の制御を行うコンポーネント.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Scroller : UIBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler
|
public class Scroller : UIBehaviour, IPointerUpHandler, IPointerDownHandler, IBeginDragHandler, IEndDragHandler, IDragHandler, IScrollHandler
|
||||||
{
|
{
|
||||||
[SerializeField] RectTransform viewport = default;
|
[SerializeField] RectTransform viewport = default;
|
||||||
|
|
||||||
|
@ -83,9 +83,7 @@ namespace UnityEngine.UI.Extensions
|
||||||
set => decelerationRate = value;
|
set => decelerationRate = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[SerializeField]
|
[SerializeField] Snap snap = new Snap {
|
||||||
Snap snap = new Snap
|
|
||||||
{
|
|
||||||
Enable = true,
|
Enable = true,
|
||||||
VelocityThreshold = 0.5f,
|
VelocityThreshold = 0.5f,
|
||||||
Duration = 0.3f,
|
Duration = 0.3f,
|
||||||
|
@ -151,6 +149,8 @@ namespace UnityEngine.UI.Extensions
|
||||||
|
|
||||||
int totalCount;
|
int totalCount;
|
||||||
|
|
||||||
|
bool hold;
|
||||||
|
bool scrolling;
|
||||||
bool dragging;
|
bool dragging;
|
||||||
float velocity;
|
float velocity;
|
||||||
|
|
||||||
|
@ -163,14 +163,14 @@ namespace UnityEngine.UI.Extensions
|
||||||
public Ease Easing;
|
public Ease Easing;
|
||||||
}
|
}
|
||||||
|
|
||||||
static readonly Func<float, float> DefaultEasingFunction = EasingFunction.Get(Ease.OutCubic);
|
static readonly EasingFunction DefaultEasingFunction = Easing.Get(Ease.OutCubic);
|
||||||
|
|
||||||
class AutoScrollState
|
class AutoScrollState
|
||||||
{
|
{
|
||||||
public bool Enable;
|
public bool Enable;
|
||||||
public bool Elastic;
|
public bool Elastic;
|
||||||
public float Duration;
|
public float Duration;
|
||||||
public Func<float, float> EasingFunction;
|
public EasingFunction EasingFunction;
|
||||||
public float StartTime;
|
public float StartTime;
|
||||||
public float EndPosition;
|
public float EndPosition;
|
||||||
|
|
||||||
|
@ -240,7 +240,7 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// <param name="duration">移動にかける秒数.</param>
|
/// <param name="duration">移動にかける秒数.</param>
|
||||||
/// <param name="easing">移動に使用するイージング.</param>
|
/// <param name="easing">移動に使用するイージング.</param>
|
||||||
/// <param name="onComplete">移動が完了した際に呼び出されるコールバック.</param>
|
/// <param name="onComplete">移動が完了した際に呼び出されるコールバック.</param>
|
||||||
public void ScrollTo(float position, float duration, Ease easing, Action onComplete = null) => ScrollTo(position, duration, EasingFunction.Get(easing), onComplete);
|
public void ScrollTo(float position, float duration, Ease easing, Action onComplete = null) => ScrollTo(position, duration, Easing.Get(easing), onComplete);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 指定した位置まで移動します.
|
/// 指定した位置まで移動します.
|
||||||
|
@ -249,7 +249,7 @@ namespace UnityEngine.UI.Extensions
|
||||||
/// <param name="duration">移動にかける秒数.</param>
|
/// <param name="duration">移動にかける秒数.</param>
|
||||||
/// <param name="easingFunction">移動に使用するイージング関数.</param>
|
/// <param name="easingFunction">移動に使用するイージング関数.</param>
|
||||||
/// <param name="onComplete">移動が完了した際に呼び出されるコールバック.</param>
|
/// <param name="onComplete">移動が完了した際に呼び出されるコールバック.</param>
|
||||||
public void ScrollTo(float position, float duration, Func<float, float> easingFunction, Action onComplete = null)
|
public void ScrollTo(float position, float duration, EasingFunction easingFunction, Action onComplete = null)
|
||||||
{
|
{
|
||||||
if (duration <= 0f)
|
if (duration <= 0f)
|
||||||
{
|
{
|
||||||
|
@ -283,13 +283,8 @@ namespace UnityEngine.UI.Extensions
|
||||||
throw new ArgumentOutOfRangeException(nameof(index));
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
autoScrollState.Reset();
|
|
||||||
|
|
||||||
velocity = 0f;
|
|
||||||
dragging = false;
|
|
||||||
|
|
||||||
UpdateSelection(index);
|
UpdateSelection(index);
|
||||||
UpdatePosition(index);
|
Position = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -311,6 +306,75 @@ namespace UnityEngine.UI.Extensions
|
||||||
: MovementDirection.Down;
|
: MovementDirection.Down;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
void IPointerDownHandler.OnPointerDown(PointerEventData eventData)
|
||||||
|
{
|
||||||
|
if (!draggable || eventData.button != PointerEventData.InputButton.Left)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hold = true;
|
||||||
|
velocity = 0f;
|
||||||
|
autoScrollState.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
void IPointerUpHandler.OnPointerUp(PointerEventData eventData)
|
||||||
|
{
|
||||||
|
if (!draggable || eventData.button != PointerEventData.InputButton.Left)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hold && snap.Enable)
|
||||||
|
{
|
||||||
|
UpdateSelection(Mathf.Clamp(Mathf.RoundToInt(currentPosition), 0, totalCount - 1));
|
||||||
|
ScrollTo(Mathf.RoundToInt(currentPosition), snap.Duration, snap.Easing);
|
||||||
|
}
|
||||||
|
|
||||||
|
hold = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
void IScrollHandler.OnScroll(PointerEventData eventData)
|
||||||
|
{
|
||||||
|
if (!draggable)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var delta = eventData.scrollDelta;
|
||||||
|
|
||||||
|
// Down is positive for scroll events, while in UI system up is positive.
|
||||||
|
delta.y *= -1;
|
||||||
|
var scrollDelta = scrollDirection == ScrollDirection.Horizontal
|
||||||
|
? Mathf.Abs(delta.y) > Mathf.Abs(delta.x)
|
||||||
|
? delta.y
|
||||||
|
: delta.x
|
||||||
|
: Mathf.Abs(delta.x) > Mathf.Abs(delta.y)
|
||||||
|
? delta.x
|
||||||
|
: delta.y;
|
||||||
|
|
||||||
|
if (eventData.IsScrolling())
|
||||||
|
{
|
||||||
|
scrolling = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var position = currentPosition + scrollDelta / ViewportSize * scrollSensitivity;
|
||||||
|
if (movementType == MovementType.Clamped)
|
||||||
|
{
|
||||||
|
position += CalculateOffset(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autoScrollState.Enable)
|
||||||
|
{
|
||||||
|
autoScrollState.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdatePosition(position);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
void IBeginDragHandler.OnBeginDrag(PointerEventData eventData)
|
void IBeginDragHandler.OnBeginDrag(PointerEventData eventData)
|
||||||
{
|
{
|
||||||
|
@ -319,6 +383,7 @@ namespace UnityEngine.UI.Extensions
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hold = false;
|
||||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
||||||
viewport,
|
viewport,
|
||||||
eventData.position,
|
eventData.position,
|
||||||
|
@ -449,7 +514,7 @@ namespace UnityEngine.UI.Extensions
|
||||||
|
|
||||||
UpdatePosition(position);
|
UpdatePosition(position);
|
||||||
}
|
}
|
||||||
else if (!dragging && (!Mathf.Approximately(offset, 0f) || !Mathf.Approximately(velocity, 0f)))
|
else if (!(dragging || scrolling) && (!Mathf.Approximately(offset, 0f) || !Mathf.Approximately(velocity, 0f)))
|
||||||
{
|
{
|
||||||
var position = currentPosition;
|
var position = currentPosition;
|
||||||
|
|
||||||
|
@ -500,13 +565,14 @@ namespace UnityEngine.UI.Extensions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!autoScrollState.Enable && dragging && inertia)
|
if (!autoScrollState.Enable && (dragging || scrolling) && inertia)
|
||||||
{
|
{
|
||||||
var newVelocity = (currentPosition - prevPosition) / deltaTime;
|
var newVelocity = (currentPosition - prevPosition) / deltaTime;
|
||||||
velocity = Mathf.Lerp(velocity, newVelocity, deltaTime * 10f);
|
velocity = Mathf.Lerp(velocity, newVelocity, deltaTime * 10f);
|
||||||
}
|
}
|
||||||
|
|
||||||
prevPosition = currentPosition;
|
prevPosition = currentPosition;
|
||||||
|
scrolling = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float CalculateMovementAmount(float sourcePosition, float destPosition)
|
float CalculateMovementAmount(float sourcePosition, float destPosition)
|
||||||
|
|
Loading…
Reference in New Issue