mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-01-07 18:13:35 +08:00
final touches on scroll pool
This commit is contained in:
parent
837d5792be
commit
29b453dc91
@ -168,7 +168,7 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rangeStart == -1)
|
if (rangeStart == -1)
|
||||||
throw new Exception($"Couldn't find range start index, rangeStart is -1.");
|
rangeStart = rangeToDataIndexCache.Count - 1;
|
||||||
|
|
||||||
if (spreadDiff > 0)
|
if (spreadDiff > 0)
|
||||||
{
|
{
|
||||||
|
@ -14,24 +14,9 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ScrollPool : UIBehaviourModel
|
public class ScrollPool : UIBehaviourModel
|
||||||
{
|
{
|
||||||
//// used to track and manage cell views
|
|
||||||
//public class CachedCell
|
|
||||||
//{
|
|
||||||
// public ScrollPool Pool { get; }
|
|
||||||
// public RectTransform Rect { get; internal set; }
|
|
||||||
// public ICell Cell { get; }
|
|
||||||
|
|
||||||
// public CachedCell(ScrollPool pool, RectTransform rect, ICell cell)
|
|
||||||
// {
|
|
||||||
// this.Pool = pool;
|
|
||||||
// this.Rect = rect;
|
|
||||||
// this.Cell = cell;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
public ScrollPool(ScrollRect scrollRect)
|
public ScrollPool(ScrollRect scrollRect)
|
||||||
{
|
{
|
||||||
this.scrollRect = scrollRect;
|
this.ScrollRect = scrollRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPoolDataSource DataSource;
|
public IPoolDataSource DataSource;
|
||||||
@ -40,18 +25,18 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
private float PrototypeHeight => PrototypeCell.rect.height;
|
private float PrototypeHeight => PrototypeCell.rect.height;
|
||||||
|
|
||||||
public int ExtraPoolCells => 10;
|
public int ExtraPoolCells => 10;
|
||||||
public float ExtraPoolThreshold => PrototypeHeight * ExtraPoolCells;
|
public float RecycleThreshold => PrototypeHeight * ExtraPoolCells;
|
||||||
public float HalfPoolThreshold => ExtraPoolThreshold * 0.5f;
|
public float HalfThreshold => RecycleThreshold * 0.5f;
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
|
|
||||||
public override GameObject UIRoot => scrollRect.gameObject;
|
public override GameObject UIRoot => ScrollRect.gameObject;
|
||||||
|
|
||||||
public RectTransform Viewport => scrollRect.viewport;
|
public RectTransform Viewport => ScrollRect.viewport;
|
||||||
public RectTransform Content => scrollRect.content;
|
public RectTransform Content => ScrollRect.content;
|
||||||
|
|
||||||
internal Slider slider;
|
internal Slider slider;
|
||||||
internal ScrollRect scrollRect;
|
internal ScrollRect ScrollRect;
|
||||||
internal VerticalLayoutGroup contentLayout;
|
internal VerticalLayoutGroup contentLayout;
|
||||||
|
|
||||||
// Cache / tracking
|
// Cache / tracking
|
||||||
@ -123,20 +108,20 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
HeightCache = new DataHeightManager(this);
|
HeightCache = new DataHeightManager(this);
|
||||||
DataSource = dataSource;
|
DataSource = dataSource;
|
||||||
|
|
||||||
this.contentLayout = scrollRect.content.GetComponent<VerticalLayoutGroup>();
|
this.contentLayout = ScrollRect.content.GetComponent<VerticalLayoutGroup>();
|
||||||
this.slider = scrollRect.GetComponentInChildren<Slider>();
|
this.slider = ScrollRect.GetComponentInChildren<Slider>();
|
||||||
slider.onValueChanged.AddListener(OnSliderValueChanged);
|
slider.onValueChanged.AddListener(OnSliderValueChanged);
|
||||||
|
|
||||||
scrollRect.vertical = true;
|
ScrollRect.vertical = true;
|
||||||
scrollRect.horizontal = false;
|
ScrollRect.horizontal = false;
|
||||||
|
|
||||||
scrollRect.onValueChanged.RemoveListener(OnValueChangedListener);
|
ScrollRect.onValueChanged.RemoveListener(OnValueChangedListener);
|
||||||
RuntimeProvider.Instance.StartCoroutine(InitCoroutine());
|
RuntimeProvider.Instance.StartCoroutine(InitCoroutine());
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerator InitCoroutine()
|
private IEnumerator InitCoroutine()
|
||||||
{
|
{
|
||||||
scrollRect.content.anchoredPosition = Vector2.zero;
|
ScrollRect.content.anchoredPosition = Vector2.zero;
|
||||||
yield return null;
|
yield return null;
|
||||||
|
|
||||||
// set intial bounds
|
// set intial bounds
|
||||||
@ -151,7 +136,7 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
UpdateSliderHandle();
|
UpdateSliderHandle();
|
||||||
|
|
||||||
// add onValueChanged listener after setup
|
// add onValueChanged listener after setup
|
||||||
scrollRect.onValueChanged.AddListener(OnValueChangedListener);
|
ScrollRect.onValueChanged.AddListener(OnValueChangedListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetScrollBounds()
|
private void SetScrollBounds()
|
||||||
@ -171,7 +156,7 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
}
|
}
|
||||||
|
|
||||||
float currentPoolCoverage = 0f;
|
float currentPoolCoverage = 0f;
|
||||||
float requiredCoverage = scrollRect.viewport.rect.height + ExtraPoolThreshold;// * ExtraPoolCoverageRatio;
|
float requiredCoverage = ScrollRect.viewport.rect.height + RecycleThreshold;
|
||||||
|
|
||||||
topPoolIndex = 0;
|
topPoolIndex = 0;
|
||||||
bottomPoolIndex = -1;
|
bottomPoolIndex = -1;
|
||||||
@ -188,7 +173,7 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
rect.name = $"Cell_{CellPool.Count + 1}";
|
rect.name = $"Cell_{CellPool.Count + 1}";
|
||||||
var cell = DataSource.CreateCell(rect);
|
var cell = DataSource.CreateCell(rect);
|
||||||
CellPool.Add(cell);
|
CellPool.Add(cell);
|
||||||
rect.SetParent(scrollRect.content, false);
|
rect.SetParent(ScrollRect.content, false);
|
||||||
|
|
||||||
currentPoolCoverage += rect.rect.height;
|
currentPoolCoverage += rect.rect.height;
|
||||||
}
|
}
|
||||||
@ -197,33 +182,41 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
bottomDataIndex = CellPool.Count - 1;
|
bottomDataIndex = CellPool.Count - 1;
|
||||||
|
|
||||||
// after creating pool, set displayed cells.
|
// after creating pool, set displayed cells.
|
||||||
for (int i = 0; i < CellPool.Count; i++)
|
var enumerator = GetPoolEnumerator();
|
||||||
SetCell(CellPool[i], i);
|
while (enumerator.MoveNext())
|
||||||
|
SetCell(CellPool[enumerator.Current.cellIndex], enumerator.Current.dataIndex);
|
||||||
|
|
||||||
LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetRecycleViewBounds(bool checkHeightGrow)
|
/// <summary>ret = cell pool was extended</summary>
|
||||||
|
private bool SetRecycleViewBounds(bool checkHeightGrow)
|
||||||
{
|
{
|
||||||
RecycleViewBounds = new Vector2(Viewport.MinY() + HalfPoolThreshold, Viewport.MaxY() - HalfPoolThreshold);
|
bool ret = false;
|
||||||
|
|
||||||
|
RecycleViewBounds = new Vector2(Viewport.MinY() + HalfThreshold, Viewport.MaxY() - HalfThreshold);
|
||||||
|
|
||||||
if (checkHeightGrow && _prevViewportHeight < Viewport.rect.height && _prevViewportHeight != 0.0f)
|
if (checkHeightGrow && _prevViewportHeight < Viewport.rect.height && _prevViewportHeight != 0.0f)
|
||||||
ExtendCellPool();
|
{
|
||||||
|
ret = ExtendCellPool();
|
||||||
|
}
|
||||||
|
|
||||||
_prevViewportHeight = Viewport.rect.height;
|
_prevViewportHeight = Viewport.rect.height;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this is working fine except the content jumps to the top while dragging (then jumps back after).
|
private bool ExtendCellPool()
|
||||||
// Not sure why, should be fixable though.
|
|
||||||
|
|
||||||
private void ExtendCellPool()
|
|
||||||
{
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
var requiredCoverage = Math.Abs(RecycleViewBounds.y - RecycleViewBounds.x);
|
var requiredCoverage = Math.Abs(RecycleViewBounds.y - RecycleViewBounds.x);
|
||||||
var currentCoverage = CellPool.Count * PrototypeHeight;
|
var currentCoverage = CellPool.Count * PrototypeHeight;
|
||||||
int cellsRequired = (int)Math.Ceiling((decimal)(requiredCoverage - currentCoverage) / (decimal)PrototypeHeight);
|
int cellsRequired = (int)Math.Ceiling((decimal)(requiredCoverage - currentCoverage) / (decimal)PrototypeHeight);
|
||||||
if (cellsRequired > 0)
|
if (cellsRequired > 0)
|
||||||
{
|
{
|
||||||
var pos = Content.anchoredPosition.y;
|
ret = true;
|
||||||
|
WritingLocked = true;
|
||||||
|
|
||||||
// Disable cells so DataSource can handle its content if need be
|
// Disable cells so DataSource can handle its content if need be
|
||||||
var enumerator = GetPoolEnumerator();
|
var enumerator = GetPoolEnumerator();
|
||||||
@ -234,19 +227,22 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
}
|
}
|
||||||
|
|
||||||
bottomDataIndex += cellsRequired;
|
bottomDataIndex += cellsRequired;
|
||||||
|
int maxDataIndex = Math.Max(CellPool.Count + cellsRequired - 1, DataSource.ItemCount - 1);
|
||||||
|
if (bottomDataIndex > maxDataIndex)
|
||||||
|
bottomDataIndex = maxDataIndex;
|
||||||
|
|
||||||
// CreateCellPool will destroy existing cells and recreate list.
|
// CreateCellPool will destroy existing cells and recreate list.
|
||||||
CreateCellPool(false);
|
CreateCellPool(false);
|
||||||
|
|
||||||
//LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
|
||||||
//scrollRect.UpdatePrevData();
|
|
||||||
|
|
||||||
// set content anchor position back
|
|
||||||
Content.anchoredPosition = new Vector2(0, pos);
|
|
||||||
|
|
||||||
LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
||||||
scrollRect.UpdatePrevData();
|
|
||||||
|
//Content.anchoredPosition = new Vector2(0, pos);
|
||||||
|
ScrollRect.UpdatePrevData();
|
||||||
|
|
||||||
|
SetScrollBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh methods
|
// Refresh methods
|
||||||
@ -279,8 +275,6 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
{
|
{
|
||||||
if (!CellPool.Any()) return;
|
if (!CellPool.Any()) return;
|
||||||
|
|
||||||
// ExplorerCore.Log("RefreshCells | " + Time.time);
|
|
||||||
|
|
||||||
SetRecycleViewBounds(true);
|
SetRecycleViewBounds(true);
|
||||||
|
|
||||||
// jump to bottom if the data count went below our bottom data index
|
// jump to bottom if the data count went below our bottom data index
|
||||||
@ -334,9 +328,8 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
}
|
}
|
||||||
|
|
||||||
LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
||||||
//SetRecycleViewBounds(false);
|
|
||||||
SetScrollBounds();
|
SetScrollBounds();
|
||||||
scrollRect.UpdatePrevData();
|
ScrollRect.UpdatePrevData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetCell(ICell cachedCell, int dataIndex)
|
private void SetCell(ICell cachedCell, int dataIndex)
|
||||||
@ -344,7 +337,6 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
cachedCell.Enable();
|
cachedCell.Enable();
|
||||||
DataSource.SetCell(cachedCell, dataIndex);
|
DataSource.SetCell(cachedCell, dataIndex);
|
||||||
|
|
||||||
// DO NEED THIS! Potentially slightly expensive, but everything breaks if we dont do this.
|
|
||||||
LayoutRebuilder.ForceRebuildLayoutImmediate(cachedCell.Rect);
|
LayoutRebuilder.ForceRebuildLayoutImmediate(cachedCell.Rect);
|
||||||
|
|
||||||
if (dataIndex < DataSource.ItemCount)
|
if (dataIndex < DataSource.ItemCount)
|
||||||
@ -358,12 +350,10 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
if (WritingLocked)
|
if (WritingLocked)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//ExplorerCore.Log("ScrollRect.OnValueChanged | " + Time.time + ", val: " + val.y.ToString("F5"));
|
if (!SetRecycleViewBounds(true))
|
||||||
|
RefreshCells();
|
||||||
|
|
||||||
SetRecycleViewBounds(true);
|
float yChange = (ScrollRect.content.anchoredPosition - _prevAnchoredPos).y;
|
||||||
RefreshCells();
|
|
||||||
|
|
||||||
float yChange = (scrollRect.content.anchoredPosition - _prevAnchoredPos).y;
|
|
||||||
float adjust = 0f;
|
float adjust = 0f;
|
||||||
|
|
||||||
if (yChange > 0) // Scrolling down
|
if (yChange > 0) // Scrolling down
|
||||||
@ -379,11 +369,11 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
}
|
}
|
||||||
|
|
||||||
var vector = new Vector2(0, adjust);
|
var vector = new Vector2(0, adjust);
|
||||||
scrollRect.m_ContentStartPosition += vector;
|
ScrollRect.m_ContentStartPosition += vector;
|
||||||
scrollRect.m_PrevPosition += vector;
|
ScrollRect.m_PrevPosition += vector;
|
||||||
|
|
||||||
LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
||||||
_prevAnchoredPos = scrollRect.content.anchoredPosition;
|
_prevAnchoredPos = ScrollRect.content.anchoredPosition;
|
||||||
|
|
||||||
SetScrollBounds();
|
SetScrollBounds();
|
||||||
|
|
||||||
@ -534,7 +524,7 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
poolStartIndex = Math.Min(DataSource.ItemCount - CellPool.Count, poolStartIndex);
|
poolStartIndex = Math.Min(DataSource.ItemCount - CellPool.Count, poolStartIndex);
|
||||||
|
|
||||||
// for content at the very top, just use the desired position as the anchor pos.
|
// for content at the very top, just use the desired position as the anchor pos.
|
||||||
if (desiredMinY < ExtraPoolThreshold * 0.5f)
|
if (desiredMinY < RecycleThreshold * 0.5f)
|
||||||
{
|
{
|
||||||
Content.anchoredPosition = new Vector2(0, desiredMinY);
|
Content.anchoredPosition = new Vector2(0, desiredMinY);
|
||||||
}
|
}
|
||||||
@ -548,17 +538,9 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
Content.anchoredPosition = new Vector2(0, diff);
|
Content.anchoredPosition = new Vector2(0, diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollRect.UpdatePrevData();
|
|
||||||
LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
|
||||||
|
|
||||||
//var pos = Content.anchoredPosition.y;
|
|
||||||
|
|
||||||
bottomDataIndex = poolStartIndex + CellPool.Count - 1;
|
bottomDataIndex = poolStartIndex + CellPool.Count - 1;
|
||||||
RefreshCells(true, false);
|
RefreshCells(true, false);
|
||||||
|
|
||||||
scrollRect.UpdatePrevData();
|
|
||||||
LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
|
||||||
|
|
||||||
UpdateSliderHandle(true);
|
UpdateSliderHandle(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user