FancyGridView.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /*
  2. * FancyScrollView (https://github.com/setchi/FancyScrollView)
  3. * Copyright (c) 2020 setchi
  4. * Licensed under MIT (https://github.com/setchi/FancyScrollView/blob/master/LICENSE)
  5. */
  6. using System;
  7. using System.Linq;
  8. using System.Collections.Generic;
  9. using UnityEngine;
  10. using EasingCore;
  11. namespace FancyScrollView
  12. {
  13. /// <summary>
  14. /// グリッドレイアウトのスクロールビューを実装するための抽象基底クラス.
  15. /// 無限スクロールおよびスナップには対応していません.
  16. /// <see cref="FancyScrollView{TItemData, TContext}.Context"/> が不要な場合は
  17. /// 代わりに <see cref="FancyGridView{TItemData}"/> を使用します.
  18. /// </summary>
  19. /// <typeparam name="TItemData">アイテムのデータ型.</typeparam>
  20. /// <typeparam name="TContext"><see cref="FancyScrollView{TItemData, TContext}.Context"/> の型.</typeparam>
  21. public abstract class FancyGridView<TItemData, TContext> : FancyScrollRect<TItemData[], TContext>
  22. where TContext : class, IFancyGridViewContext, new()
  23. {
  24. /// <summary>
  25. /// デフォルトのセルグループクラス.
  26. /// </summary>
  27. protected abstract class DefaultCellGroup : FancyCellGroup<TItemData, TContext> { }
  28. /// <summary>
  29. /// 最初にセルを配置する軸方向のセル同士の余白.
  30. /// </summary>
  31. [SerializeField] protected float startAxisSpacing = 0f;
  32. /// <summary>
  33. /// 最初にセルを配置する軸方向のセル数.
  34. /// </summary>
  35. [SerializeField] protected int startAxisCellCount = 4;
  36. /// <summary>
  37. /// セルのサイズ.
  38. /// </summary>
  39. [SerializeField] protected Vector2 cellSize = new Vector2(100f, 100f);
  40. /// <summary>
  41. /// セルのグループ Prefab.
  42. /// </summary>
  43. /// <remarks>
  44. /// <see cref="FancyGridView{TItemData, TContext}"/> では,
  45. /// <see cref="FancyScrollView{TItemData, TContext}.CellPrefab"/> を最初にセルを配置する軸方向のセルコンテナとして使用します.
  46. /// </remarks>
  47. protected sealed override GameObject CellPrefab => cellGroupTemplate;
  48. /// <inheritdoc/>
  49. protected override float CellSize => Scroller.ScrollDirection == ScrollDirection.Horizontal
  50. ? cellSize.x
  51. : cellSize.y;
  52. /// <summary>
  53. /// アイテムの総数.
  54. /// </summary>
  55. public int DataCount { get; private set; }
  56. GameObject cellGroupTemplate;
  57. /// <inheritdoc/>
  58. protected override void Initialize()
  59. {
  60. base.Initialize();
  61. Debug.Assert(startAxisCellCount > 0);
  62. Context.ScrollDirection = Scroller.ScrollDirection;
  63. Context.GetGroupCount = () => startAxisCellCount;
  64. Context.GetStartAxisSpacing = () => startAxisSpacing;
  65. Context.GetCellSize = () => Scroller.ScrollDirection == ScrollDirection.Horizontal
  66. ? cellSize.y
  67. : cellSize.x;
  68. SetupCellTemplate();
  69. }
  70. /// <summary>
  71. /// 最初にセルが生成される直前に呼び出されます.
  72. /// <see cref="Setup{TGroup}(FancyCell{TItemData, TContext})"/> メソッドを使用してセルテンプレートのセットアップを行ってください.
  73. /// </summary>
  74. /// <example>
  75. /// <code><![CDATA[
  76. /// using UnityEngine;
  77. /// using FancyScrollView;
  78. ///
  79. /// public class MyGridView : FancyGridView<ItemData, Context>
  80. /// {
  81. /// class CellGroup : DefaultCellGroup { }
  82. ///
  83. /// [SerializeField] Cell cellPrefab = default;
  84. ///
  85. /// protected override void SetupCellTemplate() => Setup<CellGroup>(cellPrefab);
  86. /// }
  87. /// ]]></code>
  88. /// </example>
  89. protected abstract void SetupCellTemplate();
  90. /// <summary>
  91. /// セルテンプレートのセットアップを行います.
  92. /// </summary>
  93. /// <param name="cellTemplate">セルのテンプレート.</param>
  94. /// <typeparam name="TGroup">セルグループの型.</typeparam>
  95. protected virtual void Setup<TGroup>(FancyCell<TItemData, TContext> cellTemplate)
  96. where TGroup : FancyCell<TItemData[], TContext>
  97. {
  98. Context.CellTemplate = cellTemplate.gameObject;
  99. cellGroupTemplate = new GameObject("Group").AddComponent<TGroup>().gameObject;
  100. cellGroupTemplate.transform.SetParent(cellContainer, false);
  101. cellGroupTemplate.SetActive(false);
  102. }
  103. /// <summary>
  104. /// 渡されたアイテム一覧に基づいて表示内容を更新します.
  105. /// </summary>
  106. /// <param name="items">アイテム一覧.</param>
  107. public virtual void UpdateContents(IList<TItemData> items)
  108. {
  109. DataCount = items.Count;
  110. var itemGroups = items
  111. .Select((item, index) => (item, index))
  112. .GroupBy(
  113. x => x.index / startAxisCellCount,
  114. x => x.item)
  115. .Select(group => group.ToArray())
  116. .ToArray();
  117. UpdateContents(itemGroups);
  118. }
  119. /// <summary>
  120. /// 指定したアイテムの位置までジャンプします.
  121. /// </summary>
  122. /// <param name="itemIndex">アイテムのインデックス.</param>
  123. /// <param name="alignment">ビューポート内におけるセル位置の基準. 0f(先頭) ~ 1f(末尾).</param>
  124. protected override void JumpTo(int itemIndex, float alignment = 0.5f)
  125. {
  126. var groupIndex = itemIndex / startAxisCellCount;
  127. base.JumpTo(groupIndex, alignment);
  128. }
  129. /// <summary>
  130. /// 指定したアイテムの位置まで移動します.
  131. /// </summary>
  132. /// <param name="itemIndex">アイテムのインデックス.</param>
  133. /// <param name="duration">移動にかける秒数.</param>
  134. /// <param name="alignment">ビューポート内におけるセル位置の基準. 0f(先頭) ~ 1f(末尾).</param>
  135. /// <param name="onComplete">移動が完了した際に呼び出されるコールバック.</param>
  136. protected override void ScrollTo(int itemIndex, float duration, float alignment = 0.5f, Action onComplete = null)
  137. {
  138. var groupIndex = itemIndex / startAxisCellCount;
  139. base.ScrollTo(groupIndex, duration, alignment, onComplete);
  140. }
  141. /// <summary>
  142. /// 指定したアイテムの位置まで移動します.
  143. /// </summary>
  144. /// <param name="itemIndex">アイテムのインデックス.</param>
  145. /// <param name="duration">移動にかける秒数.</param>
  146. /// <param name="easing">移動に使用するイージング.</param>
  147. /// <param name="alignment">ビューポート内におけるセル位置の基準. 0f(先頭) ~ 1f(末尾).</param>
  148. /// <param name="onComplete">移動が完了した際に呼び出されるコールバック.</param>
  149. protected override void ScrollTo(int itemIndex, float duration, Ease easing, float alignment = 0.5f, Action onComplete = null)
  150. {
  151. var groupIndex = itemIndex / startAxisCellCount;
  152. base.ScrollTo(groupIndex, duration, easing, alignment, onComplete);
  153. }
  154. }
  155. /// <summary>
  156. /// グリッドレイアウトのスクロールビューを実装するための抽象基底クラス.
  157. /// 無限スクロールおよびスナップには対応していません.
  158. /// </summary>
  159. /// <typeparam name="TItemData">アイテムのデータ型.</typeparam>
  160. /// <seealso cref="FancyGridView{TItemData, TContext}"/>
  161. public abstract class FancyGridView<TItemData> : FancyGridView<TItemData, FancyGridViewContext> { }
  162. }