mirror of
https://github.com/GrahamKracker/UnityExplorer.git
synced 2025-07-14 07:37:06 +08:00
Cleanup, use Time.realTimeSinceStartup instead of Time.time, add some stuff
This commit is contained in:
@ -28,7 +28,7 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
suggestions.Clear();
|
||||
AutoCompleter.Instance.SetSuggestions(suggestions);
|
||||
|
||||
timeOfLastCheck = Time.time;
|
||||
timeOfLastCheck = Time.realtimeSinceStartup;
|
||||
InputField.text = suggestion.UnderlyingValue;
|
||||
}
|
||||
|
||||
@ -84,10 +84,10 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
|
||||
private void OnInputFieldChanged(string value)
|
||||
{
|
||||
if (timeOfLastCheck == Time.time)
|
||||
if (!timeOfLastCheck.OccuredEarlierThanDefault())
|
||||
return;
|
||||
|
||||
timeOfLastCheck = Time.time;
|
||||
timeOfLastCheck = Time.realtimeSinceStartup;
|
||||
|
||||
value = value ?? "";
|
||||
|
||||
|
@ -40,6 +40,47 @@ namespace UnityExplorer.UI.Widgets
|
||||
public float DefaultHeight => m_defaultHeight ?? (float)(m_defaultHeight = ScrollPool.PrototypeHeight);
|
||||
private float? m_defaultHeight;
|
||||
|
||||
/// <summary>Get the data index at the specified position of the total height cache.</summary>
|
||||
public int GetFirstDataIndexAtPosition(float desiredHeight) => GetFirstDataIndexAtPosition(desiredHeight, out _);
|
||||
|
||||
/// <summary>Get the data index and DataViewInfo at the specified position of the total height cache.</summary>
|
||||
public int GetFirstDataIndexAtPosition(float desiredHeight, out DataViewInfo cache)
|
||||
{
|
||||
cache = default;
|
||||
|
||||
if (!heightCache.Any())
|
||||
return 0;
|
||||
|
||||
int rangeIndex = GetRangeFloorOfPosition(desiredHeight);
|
||||
|
||||
// probably shouldnt happen but just in case
|
||||
if (rangeIndex < 0)
|
||||
return 0;
|
||||
if (rangeIndex >= rangeCache.Count)
|
||||
{
|
||||
int idx = ScrollPool.DataSource.ItemCount - 1;
|
||||
cache = heightCache[idx];
|
||||
return idx;
|
||||
}
|
||||
|
||||
int dataIndex = rangeCache[rangeIndex];
|
||||
cache = heightCache[dataIndex];
|
||||
|
||||
// if the DataViewInfo is outdated, need to rebuild
|
||||
int expectedMin = GetRangeCeilingOfPosition(cache.startPosition);
|
||||
int expectedMax = expectedMin + cache.normalizedSpread - 1;
|
||||
if (rangeIndex < expectedMin || rangeIndex > expectedMax)
|
||||
{
|
||||
RecalculateStartPositions(Math.Max(dataIndex, expectedMax));
|
||||
|
||||
rangeIndex = GetRangeFloorOfPosition(desiredHeight);
|
||||
dataIndex = rangeCache[rangeIndex];
|
||||
cache = heightCache[dataIndex];
|
||||
}
|
||||
|
||||
return dataIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lookup table for "which data index first appears at this position"<br/>
|
||||
/// Index: DefaultHeight * index from top of data<br/>
|
||||
@ -48,7 +89,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
private readonly List<int> rangeCache = new List<int>();
|
||||
|
||||
/// <summary>Get the first range (division of DefaultHeight) which the position appears in.</summary>
|
||||
private int GetRangeIndexOfPosition(float position) => (int)Math.Floor((decimal)position / (decimal)DefaultHeight);
|
||||
private int GetRangeFloorOfPosition(float position) => (int)Math.Floor((decimal)position / (decimal)DefaultHeight);
|
||||
|
||||
/// <summary>Same as GetRangeIndexOfPosition, except this rounds up to the next division if there was remainder from the previous cell.</summary>
|
||||
private int GetRangeCeilingOfPosition(float position) => (int)Math.Ceiling((decimal)position / (decimal)DefaultHeight);
|
||||
@ -106,33 +147,6 @@ namespace UnityExplorer.UI.Widgets
|
||||
rangeCache.RemoveAt(rangeCache.Count - 1);
|
||||
}
|
||||
|
||||
/// <summary>Get the data index at the specified position of the total height cache.</summary>
|
||||
public int GetDataIndexAtPosition(float desiredHeight) => GetDataIndexAtPosition(desiredHeight, out _);
|
||||
|
||||
/// <summary>Get the data index and DataViewInfo at the specified position of the total height cache.</summary>
|
||||
public int GetDataIndexAtPosition(float desiredHeight, out DataViewInfo cache)
|
||||
{
|
||||
cache = default;
|
||||
|
||||
if (!heightCache.Any())
|
||||
return 0;
|
||||
|
||||
int rangeIndex = GetRangeIndexOfPosition(desiredHeight);
|
||||
|
||||
if (rangeIndex < 0)
|
||||
return 0;
|
||||
if (rangeIndex >= rangeCache.Count)
|
||||
{
|
||||
int idx = ScrollPool.DataSource.ItemCount - 1;
|
||||
cache = heightCache[idx];
|
||||
return idx;
|
||||
}
|
||||
|
||||
int dataIndex = rangeCache[rangeIndex];
|
||||
cache = heightCache[dataIndex];
|
||||
return dataIndex;
|
||||
}
|
||||
|
||||
/// <summary>Set a given data index with the specified value.</summary>
|
||||
public void SetIndex(int dataIndex, float height)
|
||||
{
|
||||
@ -192,8 +206,6 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
if (spread != cache.normalizedSpread)
|
||||
{
|
||||
ExplorerCore.Log("Updating spread for " + dataIndex + " from " + cache.normalizedSpread + " to " + spread);
|
||||
|
||||
int spreadDiff = spread - cache.normalizedSpread;
|
||||
cache.normalizedSpread = spread;
|
||||
|
||||
@ -217,7 +229,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
private void RecalculateStartPositions(int toIndex)
|
||||
{
|
||||
if (heightCache.Count < 2)
|
||||
if (heightCache.Count <= 1)
|
||||
return;
|
||||
|
||||
DataViewInfo cache;
|
||||
|
@ -8,6 +8,7 @@ using UnityEngine.UI;
|
||||
using UnityExplorer.Core.Input;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.ObjectPool;
|
||||
using UnityExplorer.UI.Panels;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
@ -35,7 +36,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
public float PrototypeHeight => _protoHeight ?? (float)(_protoHeight = Pool<T>.Instance.DefaultHeight);
|
||||
private float? _protoHeight;
|
||||
|
||||
public int ExtraPoolCells => 6;
|
||||
public int ExtraPoolCells => 10;
|
||||
public float RecycleThreshold => PrototypeHeight * ExtraPoolCells;
|
||||
public float HalfThreshold => RecycleThreshold * 0.5f;
|
||||
|
||||
@ -85,12 +86,12 @@ namespace UnityExplorer.UI.Widgets
|
||||
// A sanity check so only one thing is setting the value per frame.
|
||||
public bool WritingLocked
|
||||
{
|
||||
get => writingLocked;
|
||||
get => writingLocked || PanelDragger.Resizing;
|
||||
internal set
|
||||
{
|
||||
if (writingLocked == value)
|
||||
return;
|
||||
timeofLastWriteLock = Time.time;
|
||||
timeofLastWriteLock = Time.realtimeSinceStartup;
|
||||
writingLocked = value;
|
||||
}
|
||||
}
|
||||
@ -98,28 +99,32 @@ namespace UnityExplorer.UI.Widgets
|
||||
private float timeofLastWriteLock;
|
||||
|
||||
private float prevContentHeight = 1.0f;
|
||||
private event Action onHeightChanged;
|
||||
private event Action OnHeightChanged;
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (!ScrollRect || DataSource == null)
|
||||
return;
|
||||
|
||||
if (writingLocked && timeofLastWriteLock < Time.time)
|
||||
if (writingLocked && timeofLastWriteLock.OccuredEarlierThanDefault())
|
||||
writingLocked = false;
|
||||
|
||||
if (prevContentHeight <= 1f && Content.rect.height > 1f)
|
||||
if (!writingLocked)
|
||||
{
|
||||
prevContentHeight = Content.rect.height;
|
||||
}
|
||||
else if (Content.rect.height != prevContentHeight)
|
||||
{
|
||||
prevContentHeight = Content.rect.height;
|
||||
if (!writingLocked)
|
||||
OnValueChangedListener(Vector2.zero);
|
||||
if (prevContentHeight <= 1f && Content.rect.height > 1f)
|
||||
{
|
||||
prevContentHeight = Content.rect.height;
|
||||
}
|
||||
else if (Content.rect.height != prevContentHeight)
|
||||
{
|
||||
prevContentHeight = Content.rect.height;
|
||||
if (!writingLocked)
|
||||
OnValueChangedListener(Vector2.zero);
|
||||
|
||||
onHeightChanged?.Invoke();
|
||||
OnHeightChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -189,7 +194,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
// add onValueChanged listener after setup
|
||||
ScrollRect.onValueChanged.AddListener(OnValueChangedListener);
|
||||
|
||||
onHeightChanged += onHeightChangedListener;
|
||||
OnHeightChanged += onHeightChangedListener;
|
||||
onHeightChangedListener?.Invoke();
|
||||
}
|
||||
|
||||
@ -244,6 +249,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
topPoolIndex = 0;
|
||||
bottomPoolIndex = -1;
|
||||
|
||||
WritingLocked = true;
|
||||
// create cells until the Pool area is covered.
|
||||
// use minimum default height so that maximum pool count is reached.
|
||||
while (currentPoolCoverage <= requiredCoverage)
|
||||
@ -450,9 +456,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
prevAnchoredPos = ScrollRect.content.anchoredPosition;
|
||||
|
||||
SetScrollBounds();
|
||||
|
||||
//WritingLocked = true;
|
||||
UpdateSliderHandle(true);
|
||||
UpdateSliderHandle();
|
||||
}
|
||||
|
||||
private bool ShouldRecycleTop => GetCellExtent(CellPool[topPoolIndex].Rect) > RecycleViewBounds.x
|
||||
@ -465,12 +469,11 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
private float RecycleTopToBottom()
|
||||
{
|
||||
WritingLocked = true;
|
||||
|
||||
float recycledheight = 0f;
|
||||
|
||||
while (ShouldRecycleTop && CurrentDataCount < DataSource.ItemCount)
|
||||
{
|
||||
WritingLocked = true;
|
||||
var cell = CellPool[topPoolIndex];
|
||||
|
||||
//Move top cell to bottom
|
||||
@ -496,12 +499,11 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
private float RecycleBottomToTop()
|
||||
{
|
||||
WritingLocked = true;
|
||||
|
||||
float recycledheight = 0f;
|
||||
|
||||
while (ShouldRecycleBottom && CurrentDataCount > CellPool.Count)
|
||||
{
|
||||
WritingLocked = true;
|
||||
var cell = CellPool[bottomPoolIndex];
|
||||
|
||||
//Move bottom cell to top
|
||||
@ -537,74 +539,26 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
// Slider
|
||||
|
||||
private void UpdateSliderHandle(bool forcePositionValue = true)
|
||||
{
|
||||
CheckDataSourceCountChange(out _);
|
||||
|
||||
var dataHeight = TotalDataHeight;
|
||||
|
||||
// calculate handle size based on viewport / total data height
|
||||
var viewportHeight = Viewport.rect.height;
|
||||
var handleHeight = viewportHeight * Math.Min(1, viewportHeight / dataHeight);
|
||||
handleHeight = Math.Max(15f, handleHeight);
|
||||
|
||||
// resize the handle container area for the size of the handle (bigger handle = smaller container)
|
||||
var container = slider.m_HandleContainerRect;
|
||||
container.offsetMax = new Vector2(container.offsetMax.x, -(handleHeight * 0.5f));
|
||||
container.offsetMin = new Vector2(container.offsetMin.x, handleHeight * 0.5f);
|
||||
|
||||
// set handle size
|
||||
slider.handleRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, handleHeight);
|
||||
|
||||
// if slider is 100% height then make it not interactable
|
||||
slider.interactable = !Mathf.Approximately(handleHeight, viewportHeight);
|
||||
|
||||
if (forcePositionValue)
|
||||
{
|
||||
float val = 0f;
|
||||
if (TotalDataHeight > 0f)
|
||||
{
|
||||
float topPos = 0f;
|
||||
if (HeightCache.Count > 0)
|
||||
topPos = HeightCache[TopDataIndex].startPosition;
|
||||
|
||||
var scrollPos = topPos + Content.anchoredPosition.y;
|
||||
|
||||
var viewHeight = TotalDataHeight - Viewport.rect.height;
|
||||
if (viewHeight != 0.0f)
|
||||
val = (float)((decimal)scrollPos / (decimal)(viewHeight));
|
||||
else
|
||||
val = 0f;
|
||||
}
|
||||
|
||||
bool prev = writingLocked;
|
||||
WritingLocked = true;
|
||||
slider.value = val;
|
||||
WritingLocked = prev;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSliderValueChanged(float val)
|
||||
{
|
||||
if (this.WritingLocked || DataSource == null)
|
||||
// Prevent spam invokes unless value is 0 or 1 (so we dont skip over the start/end)
|
||||
if (DataSource == null || (WritingLocked && val != 0 && val != 1))
|
||||
return;
|
||||
this.WritingLocked = true;
|
||||
|
||||
ScrollRect.StopMovement();
|
||||
|
||||
RefreshCellHeightsFast();
|
||||
|
||||
// normalize the scroll position for the scroll bounds.
|
||||
// this translates the value into saying "point at the center of the height of the viewport"
|
||||
var scrollHeight = NormalizedScrollBounds.y - NormalizedScrollBounds.x;
|
||||
var desiredPosition = val * scrollHeight + NormalizedScrollBounds.x;
|
||||
// point at the center of the viewport
|
||||
var desiredPosition = val * (NormalizedScrollBounds.y - NormalizedScrollBounds.x) + NormalizedScrollBounds.x;
|
||||
|
||||
// add offset above it for viewport height
|
||||
var halfView = Viewport.rect.height * 0.5f;
|
||||
var desiredMinY = desiredPosition - halfView;
|
||||
|
||||
// get the data index at the top of the viewport
|
||||
int topViewportIndex = HeightCache.GetDataIndexAtPosition(desiredMinY);
|
||||
int topViewportIndex = HeightCache.GetFirstDataIndexAtPosition(desiredMinY);
|
||||
topViewportIndex = Math.Max(0, topViewportIndex);
|
||||
topViewportIndex = Math.Min(DataSource.ItemCount - 1, topViewportIndex);
|
||||
|
||||
@ -677,7 +631,48 @@ namespace UnityExplorer.UI.Widgets
|
||||
SetScrollBounds();
|
||||
ScrollRect.UpdatePrevData();
|
||||
|
||||
UpdateSliderHandle(false);
|
||||
UpdateSliderHandle();
|
||||
}
|
||||
|
||||
private void UpdateSliderHandle()// bool forcePositionValue = true)
|
||||
{
|
||||
CheckDataSourceCountChange(out _);
|
||||
|
||||
var dataHeight = TotalDataHeight;
|
||||
|
||||
// calculate handle size based on viewport / total data height
|
||||
var viewportHeight = Viewport.rect.height;
|
||||
var handleHeight = viewportHeight * Math.Min(1, viewportHeight / dataHeight);
|
||||
handleHeight = Math.Max(15f, handleHeight);
|
||||
|
||||
// resize the handle container area for the size of the handle (bigger handle = smaller container)
|
||||
var container = slider.m_HandleContainerRect;
|
||||
container.offsetMax = new Vector2(container.offsetMax.x, -(handleHeight * 0.5f));
|
||||
container.offsetMin = new Vector2(container.offsetMin.x, handleHeight * 0.5f);
|
||||
|
||||
// set handle size
|
||||
slider.handleRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, handleHeight);
|
||||
|
||||
// if slider is 100% height then make it not interactable
|
||||
slider.interactable = !Mathf.Approximately(handleHeight, viewportHeight);
|
||||
|
||||
float val = 0f;
|
||||
if (TotalDataHeight > 0f)
|
||||
{
|
||||
float topPos = 0f;
|
||||
if (HeightCache.Count > 0)
|
||||
topPos = HeightCache[TopDataIndex].startPosition;
|
||||
|
||||
var scrollPos = topPos + Content.anchoredPosition.y;
|
||||
|
||||
var viewHeight = TotalDataHeight - Viewport.rect.height;
|
||||
if (viewHeight != 0.0f)
|
||||
val = (float)((decimal)scrollPos / (decimal)(viewHeight));
|
||||
else
|
||||
val = 0f;
|
||||
}
|
||||
|
||||
slider.Set(val, false);
|
||||
}
|
||||
|
||||
/// <summary>Use <see cref="UIFactory.CreateScrollPool"/></summary>
|
||||
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
namespace UnityExplorer.UI
|
||||
{
|
||||
public static class UIExtension
|
||||
{
|
||||
|
Reference in New Issue
Block a user