mirror of
https://github.com/GrahamKracker/UnityExplorer.git
synced 2025-07-14 23:56:36 +08:00
Some UI cleanups, improving caching and reduce image allocation
This commit is contained in:
@ -16,7 +16,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
internal ScrollPool Scroller;
|
||||
|
||||
public int ItemCount => currentEntries.Count;
|
||||
public List<T> currentEntries;
|
||||
public readonly List<T> currentEntries = new List<T>();
|
||||
|
||||
public Func<List<T>> GetEntries;
|
||||
public Action<ButtonCell<T>, int> SetICell;
|
||||
@ -54,7 +54,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
public void RefreshData()
|
||||
{
|
||||
var allEntries = GetEntries.Invoke();
|
||||
var list = new List<T>();
|
||||
currentEntries.Clear();
|
||||
|
||||
foreach (var entry in allEntries)
|
||||
{
|
||||
@ -63,13 +63,11 @@ namespace UnityExplorer.UI.Widgets
|
||||
if (!ShouldDisplay.Invoke(entry, currentFilter))
|
||||
continue;
|
||||
|
||||
list.Add(entry);
|
||||
currentEntries.Add(entry);
|
||||
}
|
||||
else
|
||||
list.Add(entry);
|
||||
currentEntries.Add(entry);
|
||||
}
|
||||
|
||||
currentEntries = list;
|
||||
}
|
||||
|
||||
public ICell CreateCell(RectTransform rect)
|
||||
|
@ -31,9 +31,6 @@ namespace UnityExplorer.UI.CacheObject
|
||||
ConstructUI();
|
||||
UpdateValue();
|
||||
}
|
||||
|
||||
//if (!m_mainContent.activeSelf)
|
||||
// m_mainContent.SetActive(true);
|
||||
}
|
||||
|
||||
public virtual void Disable()
|
||||
@ -79,33 +76,44 @@ namespace UnityExplorer.UI.CacheObject
|
||||
internal GameObject m_parentContent;
|
||||
internal RectTransform m_mainRect;
|
||||
internal GameObject UIRoot;
|
||||
|
||||
internal GameObject SubContentGroup;
|
||||
internal bool constructedSubcontent;
|
||||
|
||||
// Make base UI holder for CacheObject, this doesnt actually display anything.
|
||||
internal virtual void ConstructUI()
|
||||
{
|
||||
m_constructedUI = true;
|
||||
|
||||
UIRoot = UIFactory.CreateVerticalGroup(m_parentContent, $"{this.GetType().Name}.MainContent", true, true, true, true, 2,
|
||||
new Vector4(0, 5, 0, 0), new Color(0.1f, 0.1f, 0.1f), TextAnchor.UpperLeft);
|
||||
//UIRoot = UIFactory.CreateVerticalGroup(m_parentContent, $"{this.GetType().Name}.MainContent", true, true, true, true, 2,
|
||||
// new Vector4(0, 5, 0, 0), new Color(0.1f, 0.1f, 0.1f), TextAnchor.UpperLeft);
|
||||
|
||||
UIRoot = UIFactory.CreateUIObject($"{this.GetType().Name}.MainContent", m_parentContent);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(UIRoot, true, true, true, true, 2, 0, 5, 0, 0, TextAnchor.UpperLeft);
|
||||
m_mainRect = UIRoot.GetComponent<RectTransform>();
|
||||
m_mainRect.pivot = new Vector2(0, 1);
|
||||
m_mainRect.anchorMin = Vector2.zero;
|
||||
m_mainRect.anchorMax = Vector2.one;
|
||||
UIFactory.SetLayoutElement(UIRoot, minHeight: 30, flexibleHeight: 9999, minWidth: 200, flexibleWidth: 5000);
|
||||
//UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
// subcontent
|
||||
|
||||
SubContentGroup = UIFactory.CreateVerticalGroup(UIRoot, $"{this.GetType().Name}.SubContent", true, false, true, true, 0, default,
|
||||
new Color(0.085f, 0.085f, 0.085f));
|
||||
SubContentGroup = new GameObject("SubContent");
|
||||
SubContentGroup.transform.parent = UIRoot.transform;
|
||||
UIFactory.SetLayoutElement(SubContentGroup, minHeight: 30, flexibleHeight: 9999, minWidth: 125, flexibleWidth: 9000);
|
||||
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(SubContentGroup, true, false, true, true);
|
||||
SubContentGroup.SetActive(false);
|
||||
|
||||
IValue.m_subContentParent = SubContentGroup;
|
||||
}
|
||||
|
||||
public virtual void CheckSubcontentCreation()
|
||||
{
|
||||
if (!constructedSubcontent)
|
||||
{
|
||||
SubContentGroup.AddComponent<Image>().color = new Color(0.08f, 0.08f, 0.08f);
|
||||
constructedSubcontent = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ namespace UnityExplorer.UI.InteractiveValues
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_recacheWanted)
|
||||
if (m_recacheWanted && Value != null)
|
||||
return true;
|
||||
else return m_entries.Count > 0;
|
||||
}
|
||||
|
@ -11,11 +11,90 @@ using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.CacheObject;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.InteractiveValues
|
||||
{
|
||||
public class InteractiveEnumerable : InteractiveValue
|
||||
public class InteractiveEnumerable : InteractiveValue, IPoolDataSource
|
||||
{
|
||||
// IPoolDataSource
|
||||
|
||||
public ScrollPool ScrollPool;
|
||||
public GameObject InactiveHolder;
|
||||
internal LayoutElement listLayout;
|
||||
|
||||
public int ItemCount => m_entries?.Count ?? 0;
|
||||
|
||||
public void SetCell(ICell icell, int index)
|
||||
{
|
||||
var cell = icell as CellViewHolder;
|
||||
|
||||
if (index < 0 || index >= ItemCount)
|
||||
{
|
||||
var existing = cell.DisableContent();
|
||||
if (existing)
|
||||
existing.transform.SetParent(InactiveHolder.transform, false);
|
||||
return;
|
||||
}
|
||||
|
||||
var cache = m_entries[index];
|
||||
cache.Enable();
|
||||
|
||||
var prev = cell.SetContent(cache.UIRoot);
|
||||
if (prev)
|
||||
prev.transform.SetParent(InactiveHolder.transform, false);
|
||||
}
|
||||
|
||||
public void DisableCell(ICell cell, int index)
|
||||
{
|
||||
var content = (cell as CellViewHolder).DisableContent();
|
||||
if (content)
|
||||
content.transform.SetParent(InactiveHolder.transform, false);
|
||||
}
|
||||
|
||||
//public void SetCell(ICell cell, int index)
|
||||
//{
|
||||
// var root = (cell as CellViewHolder).UIRoot;
|
||||
|
||||
// if (index < 0 || index >= ItemCount)
|
||||
// {
|
||||
// DisableContent(root);
|
||||
// cell.Disable();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// var cache = m_entries[index];
|
||||
// cache.Enable();
|
||||
|
||||
// var content = cache.UIRoot;
|
||||
|
||||
// if (content.transform.parent.ReferenceEqual(root.transform))
|
||||
// return;
|
||||
|
||||
// DisableContent(root);
|
||||
|
||||
// content.transform.SetParent(root.transform, false);
|
||||
//}
|
||||
|
||||
//public void DisableCell(ICell cell, int index)
|
||||
//{
|
||||
// var root = (cell as CellViewHolder).UIRoot;
|
||||
// DisableContent(root);
|
||||
// cell.Disable();
|
||||
//}
|
||||
|
||||
//private void DisableContent(GameObject cellRoot)
|
||||
//{
|
||||
// if (cellRoot.transform.childCount > 0 && cellRoot.transform.GetChild(0) is Transform existing)
|
||||
// existing.transform.SetParent(InactiveHolder.transform, false);
|
||||
//}
|
||||
|
||||
public ICell CreateCell(RectTransform cellTransform) => new CellViewHolder(cellTransform.gameObject);
|
||||
|
||||
public int GetRealIndexOfTempIndex(int tempIndex) => throw new NotImplementedException("Filtering not supported");
|
||||
|
||||
// InteractiveEnumerable
|
||||
|
||||
public InteractiveEnumerable(object value, Type valueType) : base(value, valueType)
|
||||
{
|
||||
if (valueType.IsGenericType)
|
||||
@ -30,12 +109,13 @@ namespace UnityExplorer.UI.InteractiveValues
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_recacheWanted)
|
||||
if (m_recacheWanted && Value != null)
|
||||
return true;
|
||||
else return m_entries.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal IEnumerable RefIEnumerable;
|
||||
internal IList RefIList;
|
||||
|
||||
@ -50,13 +130,14 @@ namespace UnityExplorer.UI.InteractiveValues
|
||||
RefIEnumerable = Value as IEnumerable;
|
||||
RefIList = Value as IList;
|
||||
|
||||
if (m_subContentParent.activeSelf)
|
||||
if (m_subContentParent && m_subContentParent.activeSelf)
|
||||
{
|
||||
GetCacheEntries();
|
||||
RefreshDisplay();
|
||||
ToggleSubcontent();
|
||||
//GetCacheEntries();
|
||||
//RefreshDisplay();
|
||||
}
|
||||
else
|
||||
m_recacheWanted = true;
|
||||
|
||||
m_recacheWanted = true;
|
||||
|
||||
base.OnValueUpdated();
|
||||
}
|
||||
@ -66,11 +147,6 @@ namespace UnityExplorer.UI.InteractiveValues
|
||||
base.OnException(member);
|
||||
}
|
||||
|
||||
private void OnPageTurned()
|
||||
{
|
||||
RefreshDisplay();
|
||||
}
|
||||
|
||||
public override void RefreshUIForValue()
|
||||
{
|
||||
GetDefaultLabel();
|
||||
@ -95,8 +171,6 @@ namespace UnityExplorer.UI.InteractiveValues
|
||||
{
|
||||
if (m_entries.Any())
|
||||
{
|
||||
// maybe improve this, probably could be more efficient i guess
|
||||
|
||||
foreach (var entry in m_entries)
|
||||
entry.Destroy();
|
||||
|
||||
@ -111,7 +185,7 @@ namespace UnityExplorer.UI.InteractiveValues
|
||||
int index = 0;
|
||||
foreach (var entry in RefIEnumerable)
|
||||
{
|
||||
var cache = new CacheEnumerated(index, this, RefIList, this.m_listContent);
|
||||
var cache = new CacheEnumerated(index, this, RefIList, this.InactiveHolder);
|
||||
cache.CreateIValue(entry, m_baseEntryType);
|
||||
m_entries.Add(cache);
|
||||
|
||||
@ -126,32 +200,9 @@ namespace UnityExplorer.UI.InteractiveValues
|
||||
|
||||
public void RefreshDisplay()
|
||||
{
|
||||
//var entries = m_entries;
|
||||
//m_pageHandler.ListCount = entries.Count;
|
||||
//
|
||||
//for (int i = 0; i < m_displayedEntries.Length; i++)
|
||||
//{
|
||||
// var entry = m_displayedEntries[i];
|
||||
// if (entry != null)
|
||||
// entry.Disable();
|
||||
// else
|
||||
// break;
|
||||
//}
|
||||
//
|
||||
//if (entries.Count < 1)
|
||||
// return;
|
||||
//
|
||||
//foreach (var itemIndex in m_pageHandler)
|
||||
//{
|
||||
// if (itemIndex >= entries.Count)
|
||||
// break;
|
||||
//
|
||||
// CacheEnumerated entry = entries[itemIndex];
|
||||
// m_displayedEntries[itemIndex - m_pageHandler.StartIndex] = entry;
|
||||
// entry.Enable();
|
||||
//}
|
||||
//
|
||||
////UpdateSubcontentHeight();
|
||||
ScrollPool.RefreshCells(true);
|
||||
|
||||
listLayout.minHeight = Math.Min(500f, m_entries.Count * 32f);
|
||||
}
|
||||
|
||||
internal override void OnToggleSubcontent(bool active)
|
||||
@ -168,39 +219,27 @@ namespace UnityExplorer.UI.InteractiveValues
|
||||
RefreshDisplay();
|
||||
}
|
||||
|
||||
|
||||
internal GameObject m_listContent;
|
||||
internal LayoutElement m_listLayout;
|
||||
|
||||
//internal PageHandler m_pageHandler;
|
||||
|
||||
public override void ConstructUI(GameObject parent, GameObject subGroup)
|
||||
{
|
||||
base.ConstructUI(parent, subGroup);
|
||||
|
||||
InactiveHolder = new GameObject("InactiveHolder");
|
||||
InactiveHolder.transform.SetParent(parent.transform, false);
|
||||
InactiveHolder.SetActive(false);
|
||||
}
|
||||
|
||||
public override void ConstructSubcontent()
|
||||
{
|
||||
base.ConstructSubcontent();
|
||||
|
||||
//m_pageHandler = new PageHandler(null);
|
||||
//m_pageHandler.ConstructUI(m_subContentParent);
|
||||
//m_pageHandler.OnPageChanged += OnPageTurned;
|
||||
ScrollPool = UIFactory.CreateScrollPool(m_subContentParent, "ListEntries", out GameObject scrollRoot, out GameObject scrollContent,
|
||||
new Color(0.05f, 0.05f, 0.05f));
|
||||
|
||||
m_listContent = UIFactory.CreateVerticalGroup(this.m_subContentParent, "EnumerableContent", true, true, true, true, 2, new Vector4(5,5,5,5),
|
||||
new Color(0.08f, 0.08f, 0.08f));
|
||||
listLayout = scrollRoot.AddComponent<LayoutElement>();
|
||||
|
||||
var scrollRect = m_listContent.GetComponent<RectTransform>();
|
||||
scrollRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 0);
|
||||
|
||||
m_listLayout = Owner.UIRoot.GetComponent<LayoutElement>();
|
||||
m_listLayout.minHeight = 25;
|
||||
m_listLayout.flexibleHeight = 0;
|
||||
Owner.m_mainRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 25);
|
||||
|
||||
var contentFitter = m_listContent.AddComponent<ContentSizeFitter>();
|
||||
contentFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
|
||||
contentFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
var proto = CellViewHolder.CreatePrototypeCell(scrollRoot);
|
||||
proto.sizeDelta = new Vector2(100, 30);
|
||||
ScrollPool.Initialize(this, proto);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,6 +67,9 @@ namespace UnityExplorer.UI.InteractiveValues
|
||||
if (_typeSupportCache.TryGetValue(type.AssemblyQualifiedName, out bool ret))
|
||||
return ret;
|
||||
|
||||
if (type.FullName == "System.Void")
|
||||
return false;
|
||||
|
||||
ret = true;
|
||||
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
|
||||
foreach (var field in fields)
|
||||
|
@ -172,6 +172,8 @@ namespace UnityExplorer.UI.InteractiveValues
|
||||
|
||||
public virtual void ConstructSubcontent()
|
||||
{
|
||||
Owner.CheckSubcontentCreation();
|
||||
|
||||
m_subContentConstructed = true;
|
||||
}
|
||||
|
||||
@ -305,8 +307,11 @@ namespace UnityExplorer.UI.InteractiveValues
|
||||
{
|
||||
m_UIConstructed = true;
|
||||
|
||||
m_mainContent = UIFactory.CreateHorizontalGroup(parent, $"InteractiveValue_{this.GetType().Name}", false, false, true, true, 4, default,
|
||||
new Color(1, 1, 1, 0), TextAnchor.UpperLeft);
|
||||
//m_mainContent = UIFactory.CreateHorizontalGroup(parent, $"InteractiveValue_{this.GetType().Name}", false, false, true, true, 4, default,
|
||||
// new Color(1, 1, 1, 0), TextAnchor.UpperLeft);
|
||||
|
||||
m_mainContent = UIFactory.CreateUIObject($"InteractiveValue_{this.GetType().Name}", parent);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(m_mainContent, false, false, true, true, 4, 0, 0, 0, 0, TextAnchor.UpperLeft);
|
||||
|
||||
var mainRect = m_mainContent.GetComponent<RectTransform>();
|
||||
mainRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 25);
|
||||
@ -316,7 +321,7 @@ namespace UnityExplorer.UI.InteractiveValues
|
||||
// subcontent expand button
|
||||
if (HasSubContent)
|
||||
{
|
||||
m_subExpandBtn = UIFactory.CreateButton(m_mainContent, "ExpandSubcontentButton", "▲", ToggleSubcontent, new Color(0.3f, 0.3f, 0.3f));
|
||||
m_subExpandBtn = UIFactory.CreateButton(m_mainContent, "ExpandSubcontentButton", "▲", ToggleSubcontent, new Color(1,1,1,0));
|
||||
UIFactory.SetLayoutElement(m_subExpandBtn.gameObject, minHeight: 25, minWidth: 25, flexibleWidth: 0, flexibleHeight: 0);
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,8 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
public void DoSearch()
|
||||
{
|
||||
cachedCellTexts.Clear();
|
||||
|
||||
if (m_context == SearchContext.Singleton)
|
||||
currentResults = SearchProvider.SingletonSearch(nameInputField.text);
|
||||
else if (m_context == SearchContext.StaticClass)
|
||||
@ -85,20 +87,29 @@ namespace UnityExplorer.UI.Widgets
|
||||
resultsLabel.text = $"{currentResults.Count} results";
|
||||
}
|
||||
|
||||
// Cache the syntax-highlighted text for each search result to reduce allocs.
|
||||
private static readonly Dictionary<int, string> cachedCellTexts = new Dictionary<int, string>();
|
||||
|
||||
public void SetCell(ButtonCell<object> cell, int index)
|
||||
{
|
||||
if (m_context == SearchContext.StaticClass)
|
||||
if (!cachedCellTexts.ContainsKey(index))
|
||||
{
|
||||
cell.buttonText.text = SignatureHighlighter.HighlightTypeName(currentResults[index].GetActualType());
|
||||
string text;
|
||||
if (m_context == SearchContext.StaticClass)
|
||||
text = SignatureHighlighter.HighlightTypeName(currentResults[index].GetActualType());
|
||||
else
|
||||
text = ToStringUtility.ToString(currentResults[index], currentResults[index].GetActualType());
|
||||
|
||||
cachedCellTexts.Add(index, text);
|
||||
}
|
||||
else
|
||||
cell.buttonText.text = ToStringUtility.ToString(currentResults[index], currentResults[index].GetActualType());
|
||||
|
||||
cell.buttonText.text = cachedCellTexts[index];
|
||||
}
|
||||
|
||||
private void OnCellClicked(int dataIndex)
|
||||
{
|
||||
if (m_context == SearchContext.StaticClass)
|
||||
InspectorManager.InspectType(currentResults[dataIndex] as Type);
|
||||
InspectorManager.Inspect(currentResults[dataIndex] as Type);
|
||||
else
|
||||
InspectorManager.Inspect(currentResults[dataIndex]);
|
||||
}
|
||||
|
@ -12,33 +12,57 @@ namespace UnityExplorer.UI.Widgets
|
||||
public CellViewHolder(GameObject uiRoot)
|
||||
{
|
||||
this.UIRoot = uiRoot;
|
||||
this.m_rect = uiRoot.GetComponent<RectTransform>();
|
||||
this.Rect = uiRoot.GetComponent<RectTransform>();
|
||||
m_enabled = uiRoot.activeSelf;
|
||||
}
|
||||
|
||||
public bool Enabled => m_enabled;
|
||||
private bool m_enabled;
|
||||
|
||||
public GameObject UIRoot;
|
||||
public RectTransform Rect => m_rect;
|
||||
private RectTransform m_rect;
|
||||
public GameObject UIRoot { get; }
|
||||
public RectTransform Rect { get; }
|
||||
|
||||
public void Disable()
|
||||
private GameObject m_content;
|
||||
|
||||
public GameObject SetContent(GameObject newContent)
|
||||
{
|
||||
m_enabled = false;
|
||||
UIRoot.SetActive(false);
|
||||
var ret = m_content;
|
||||
|
||||
if (ret && newContent && ret.ReferenceEqual(newContent))
|
||||
return null;
|
||||
|
||||
newContent.transform.SetParent(this.UIRoot.transform, false);
|
||||
(this as ICell).Enable();
|
||||
|
||||
m_content = newContent;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void Enable()
|
||||
public GameObject DisableContent()
|
||||
{
|
||||
var ret = m_content;
|
||||
(this as ICell).Disable();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ICell.Enable()
|
||||
{
|
||||
m_enabled = true;
|
||||
UIRoot.SetActive(true);
|
||||
}
|
||||
|
||||
void ICell.Disable()
|
||||
{
|
||||
m_enabled = false;
|
||||
UIRoot.SetActive(false);
|
||||
}
|
||||
|
||||
public static RectTransform CreatePrototypeCell(GameObject parent)
|
||||
{
|
||||
var prototype = UIFactory.CreateVerticalGroup(parent, "PrototypeCell", true, true, true, true, 0, new Vector4(1, 0, 0, 0),
|
||||
new Color(0.15f, 0.15f, 0.15f), TextAnchor.MiddleCenter);
|
||||
// using an image on the cell view holder is fine, we only need to make about 20-50 of these per pool.
|
||||
var prototype = UIFactory.CreateVerticalGroup(parent, "PrototypeCell", true, true, true, true, 0, new Vector4(0, 0, 0, 0),
|
||||
new Color(0.11f, 0.11f, 0.11f), TextAnchor.MiddleCenter);
|
||||
|
||||
var rect = prototype.GetComponent<RectTransform>();
|
||||
rect.anchorMin = new Vector2(0, 1);
|
||||
rect.anchorMax = new Vector2(0, 1);
|
||||
@ -47,6 +71,10 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
prototype.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
var sepObj = UIFactory.CreateUIObject("separator", prototype);
|
||||
sepObj.AddComponent<Image>().color = Color.black;
|
||||
UIFactory.SetLayoutElement(sepObj, minHeight: 1, preferredHeight: 1, flexibleHeight: 0);
|
||||
|
||||
prototype.SetActive(false);
|
||||
|
||||
return rect;
|
||||
|
@ -18,22 +18,14 @@ namespace UnityExplorer.UI.Widgets
|
||||
public class DataHeightCache
|
||||
{
|
||||
private ScrollPool ScrollPool { get; }
|
||||
//private DataHeightCache SisterCache { get; }
|
||||
|
||||
public DataHeightCache(ScrollPool scrollPool)
|
||||
{
|
||||
ScrollPool = scrollPool;
|
||||
}
|
||||
|
||||
public DataHeightCache(ScrollPool scrollPool, DataHeightCache sisterCache) : this(scrollPool)
|
||||
{
|
||||
//this.SisterCache = sisterCache;
|
||||
|
||||
//for (int i = 0; i < scrollPool.DataSource.ItemCount; i++)
|
||||
// Add(sisterCache[ScrollPool.DataSource.GetRealIndexOfTempIndex(i)]);
|
||||
}
|
||||
|
||||
private readonly List<DataViewInfo> heightCache = new List<DataViewInfo>();
|
||||
// initialize with a reasonably sized pool, most caches will allocate a fair bit.
|
||||
private readonly List<DataViewInfo> heightCache = new List<DataViewInfo>(16384);
|
||||
|
||||
public DataViewInfo this[int index]
|
||||
{
|
||||
@ -118,14 +110,23 @@ namespace UnityExplorer.UI.Widgets
|
||||
/// <summary>Get the data index at the specific position of the total height cache.</summary>
|
||||
public int GetDataIndexAtPosition(float desiredHeight, out DataViewInfo cache)
|
||||
{
|
||||
cache = null;
|
||||
cache = default;
|
||||
int rangeIndex = GetRangeIndexOfPosition(desiredHeight);
|
||||
|
||||
if (rangeIndex < 0)
|
||||
throw new Exception("Range index (" + rangeIndex + ") is below 0");
|
||||
{
|
||||
ExplorerCore.LogWarning("RangeIndex < 0? " + rangeIndex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rangeCache.Count <= rangeIndex)
|
||||
throw new Exception("Range index (" + rangeIndex + ") exceeded rangeCache count (" + rangeCache.Count + ")");
|
||||
{
|
||||
ExplorerCore.LogWarning("Want range index " + rangeIndex + " but count is " + rangeCache.Count);
|
||||
RebuildCache();
|
||||
rangeIndex = GetRangeIndexOfPosition(desiredHeight);
|
||||
if (rangeCache.Count <= rangeIndex)
|
||||
throw new Exception("Range index (" + rangeIndex + ") exceeded rangeCache count (" + rangeCache.Count + ")");
|
||||
}
|
||||
|
||||
int dataIndex = rangeCache[rangeIndex];
|
||||
cache = heightCache[dataIndex];
|
||||
@ -134,16 +135,13 @@ namespace UnityExplorer.UI.Widgets
|
||||
}
|
||||
|
||||
/// <summary>Set a given data index with the specified value.</summary>
|
||||
public void SetIndex(int dataIndex, float height, bool ignoreDataCount = false)
|
||||
public void SetIndex(int dataIndex, float height)
|
||||
{
|
||||
if (!ignoreDataCount)
|
||||
if (dataIndex >= ScrollPool.DataSource.ItemCount)
|
||||
{
|
||||
if (dataIndex >= ScrollPool.DataSource.ItemCount)
|
||||
{
|
||||
while (heightCache.Count > dataIndex)
|
||||
RemoveLast();
|
||||
return;
|
||||
}
|
||||
while (heightCache.Count > dataIndex)
|
||||
RemoveLast();
|
||||
return;
|
||||
}
|
||||
|
||||
if (dataIndex >= heightCache.Count)
|
||||
@ -175,14 +173,10 @@ namespace UnityExplorer.UI.Widgets
|
||||
int rangeIndex = GetRangeCeilingOfPosition(cache.startPosition);
|
||||
int spread = GetRangeSpread(cache.startPosition, height);
|
||||
|
||||
// check if our range cache is "corrupt" or not. If so we need to do a quick rebuild,
|
||||
// so that each cell's start position is correct again.
|
||||
if (rangeCache.Count <= rangeIndex || rangeCache[rangeIndex] != dataIndex)
|
||||
if (rangeCache.Count <= rangeIndex)
|
||||
{
|
||||
RebuildStartPositions(ignoreDataCount);
|
||||
// get these values again after rebuilding
|
||||
rangeIndex = GetRangeCeilingOfPosition(cache.startPosition);
|
||||
spread = GetRangeSpread(cache.startPosition, height);
|
||||
RebuildCache();
|
||||
return;
|
||||
}
|
||||
|
||||
if (spread != cache.normalizedSpread)
|
||||
@ -196,7 +190,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
// In some rare cases we may not find our data index at the expected range index.
|
||||
// We can make some educated guesses and find the real index pretty quickly.
|
||||
int minStart = rangeCache[dataIndex];
|
||||
int minStart = GetRangeIndexOfPosition(dataIndex * DefaultHeight);
|
||||
for (int i = minStart; i < rangeCache.Count; i++)
|
||||
{
|
||||
if (rangeCache[i] == dataIndex)
|
||||
@ -211,16 +205,16 @@ namespace UnityExplorer.UI.Widgets
|
||||
// This should never happen. We might be in a rebuild right now so don't
|
||||
// rebuild again, we could overflow the stack. Just log it.
|
||||
ExplorerCore.LogWarning($"DataHeightCache: Looking for range index of data {dataIndex} but reached the end and didn't find it.");
|
||||
ExplorerCore.Log($"startPos: {cache.startPosition}, rangeIndex: {rangeIndex}, total height: {TotalHeight}");
|
||||
return;
|
||||
}
|
||||
|
||||
// our data index is further down. add the min difference and try again.
|
||||
// the iterator will add 1 on the next loop so account for that.
|
||||
// also, add the (spread - 1) of the cell we found at this index to skip it.
|
||||
var spreadCurr = heightCache[rangeCache[i]].normalizedSpread;
|
||||
int jmp = dataIndex - rangeCache[i] - 1;
|
||||
jmp += heightCache[rangeCache[i]].normalizedSpread - 1;
|
||||
i += jmp < 1 ? 0 : jmp;
|
||||
jmp += spreadCurr - 2;
|
||||
i = (jmp < 1 ? i : i + jmp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,19 +226,19 @@ namespace UnityExplorer.UI.Widgets
|
||||
if (rangeCache[rangeIndex] == dataIndex)
|
||||
rangeCache.Insert(rangeIndex, dataIndex);
|
||||
else
|
||||
ExplorerCore.LogWarning($"DataHeightCache error increasing spread of data {dataIndex}, " +
|
||||
$"the value at range {rangeIndex} is {rangeCache[rangeIndex]}!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// need to remove
|
||||
for (int i = 0; i < -spreadDiff; i++)
|
||||
{
|
||||
if (rangeCache[rangeIndex] == dataIndex)
|
||||
rangeCache.RemoveAt(rangeIndex);
|
||||
else
|
||||
ExplorerCore.LogWarning($"DataHeightCache error decreasing spread of data {dataIndex}, " +
|
||||
$"the value at range {rangeIndex} is {rangeCache[rangeIndex]}!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -257,11 +251,11 @@ namespace UnityExplorer.UI.Widgets
|
||||
//}
|
||||
}
|
||||
|
||||
private void RebuildStartPositions(bool ignoreDataCount)
|
||||
private void RebuildCache()
|
||||
{
|
||||
//start at 1 because 0's start pos is always 0
|
||||
for (int i = 1; i < heightCache.Count; i++)
|
||||
SetIndex(i, heightCache[i].height, ignoreDataCount);
|
||||
SetIndex(i, heightCache[i].height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,11 @@ using UnityExplorer.UI.Models;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
public struct CellInfo
|
||||
{
|
||||
public int cellIndex, dataIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An object-pooled ScrollRect, attempts to support content of any size and provide a scrollbar for it.
|
||||
/// </summary>
|
||||
@ -62,7 +67,6 @@ namespace UnityExplorer.UI.Widgets
|
||||
private readonly List<ICell> CellPool = new List<ICell>();
|
||||
|
||||
internal DataHeightCache HeightCache;
|
||||
internal DataHeightCache tempHeightCache;
|
||||
|
||||
private float TotalDataHeight => HeightCache.TotalHeight + contentLayout.padding.top + contentLayout.padding.bottom;
|
||||
|
||||
@ -114,7 +118,10 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
public void Rebuild()
|
||||
{
|
||||
RecreateCellPool(true, true, null);
|
||||
SetRecycleViewBounds(false);
|
||||
SetScrollBounds();
|
||||
|
||||
RecreateCellPool(true, true);
|
||||
writingLocked = false;
|
||||
Content.anchoredPosition = Vector2.zero;
|
||||
UpdateSliderHandle(true);
|
||||
@ -128,22 +135,23 @@ namespace UnityExplorer.UI.Widgets
|
||||
UpdateSliderHandle(true);
|
||||
}
|
||||
|
||||
public void EnableTempCache()
|
||||
public void RecreateHeightCache()
|
||||
{
|
||||
if (tempHeightCache == null)
|
||||
tempHeightCache = HeightCache;
|
||||
//if (tempHeightCache == null)
|
||||
// tempHeightCache = HeightCache;
|
||||
|
||||
HeightCache = new DataHeightCache(this, tempHeightCache);
|
||||
HeightCache = new DataHeightCache(this);
|
||||
CheckDataSourceCountChange(out _);
|
||||
}
|
||||
|
||||
public void DisableTempCache()
|
||||
{
|
||||
if (tempHeightCache == null)
|
||||
return;
|
||||
//public void DisableTempCache()
|
||||
//{
|
||||
// if (tempHeightCache == null)
|
||||
// return;
|
||||
|
||||
HeightCache = tempHeightCache;
|
||||
tempHeightCache = null;
|
||||
}
|
||||
// HeightCache = tempHeightCache;
|
||||
// tempHeightCache = null;
|
||||
//}
|
||||
|
||||
public void RefreshCells(bool reloadData)
|
||||
{
|
||||
@ -252,23 +260,15 @@ namespace UnityExplorer.UI.Widgets
|
||||
RecycleViewBounds = new Vector2(Viewport.MinY() + HalfThreshold, Viewport.MaxY() - HalfThreshold);
|
||||
|
||||
if (checkHeightGrow && prevViewportHeight < Viewport.rect.height && prevViewportHeight != 0.0f)
|
||||
ret = RecreateCellPool(false, false, null);
|
||||
ret = RecreateCellPool(false, false);
|
||||
|
||||
prevViewportHeight = Viewport.rect.height;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool RecreateCellPool(bool forceRecreate, bool resetDataIndex, bool? setTempCacheEnabledTo)
|
||||
private bool RecreateCellPool(bool forceRecreate, bool resetDataIndex)
|
||||
{
|
||||
if (setTempCacheEnabledTo != null)
|
||||
{
|
||||
if (setTempCacheEnabledTo == true)
|
||||
EnableTempCache();
|
||||
else if (setTempCacheEnabledTo == false)
|
||||
DisableTempCache();
|
||||
}
|
||||
|
||||
CheckDataSourceCountChange(out _);
|
||||
|
||||
var requiredCoverage = Math.Abs(RecycleViewBounds.y - RecycleViewBounds.x);
|
||||
@ -310,7 +310,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
// Refresh methods
|
||||
|
||||
private struct CellInfo { public int cellIndex, dataIndex; }
|
||||
private CellInfo _cellInfo = new CellInfo();
|
||||
|
||||
private IEnumerator<CellInfo> GetPoolEnumerator()
|
||||
{
|
||||
@ -319,11 +319,9 @@ namespace UnityExplorer.UI.Widgets
|
||||
int iterated = 0;
|
||||
while (iterated < CellPool.Count)
|
||||
{
|
||||
yield return new CellInfo()
|
||||
{
|
||||
cellIndex = cellIdx,
|
||||
dataIndex = dataIndex
|
||||
};
|
||||
_cellInfo.cellIndex = cellIdx;
|
||||
_cellInfo.dataIndex = dataIndex;
|
||||
yield return _cellInfo;
|
||||
|
||||
cellIdx++;
|
||||
if (cellIdx >= CellPool.Count)
|
||||
@ -407,7 +405,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
cachedCell.Enable();
|
||||
DataSource.SetCell(cachedCell, dataIndex);
|
||||
|
||||
//LayoutRebuilder.ForceRebuildLayoutImmediate(cachedCell.Rect);
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(cachedCell.Rect);
|
||||
HeightCache.SetIndex(dataIndex, cachedCell.Rect.rect.height);
|
||||
}
|
||||
|
||||
@ -443,11 +441,11 @@ namespace UnityExplorer.UI.Widgets
|
||||
ScrollRect.m_ContentStartPosition += vector;
|
||||
ScrollRect.m_PrevPosition += vector;
|
||||
|
||||
// LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
||||
prevAnchoredPos = ScrollRect.content.anchoredPosition;
|
||||
|
||||
SetScrollBounds();
|
||||
|
||||
//WritingLocked = true;
|
||||
UpdateSliderHandle();
|
||||
}
|
||||
|
||||
@ -487,6 +485,8 @@ namespace UnityExplorer.UI.Widgets
|
||||
topPoolIndex = (topPoolIndex + 1) % CellPool.Count;
|
||||
}
|
||||
|
||||
//LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
||||
|
||||
return -recycledheight;
|
||||
}
|
||||
|
||||
@ -528,6 +528,8 @@ namespace UnityExplorer.UI.Widgets
|
||||
bottomPoolIndex = (bottomPoolIndex - 1 + CellPool.Count) % CellPool.Count;
|
||||
}
|
||||
|
||||
//LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
||||
|
||||
return recycledheight;
|
||||
}
|
||||
|
||||
|
@ -37,8 +37,6 @@ namespace UnityExplorer.UI.Utility
|
||||
|
||||
public SliderScrollbar(Scrollbar scrollbar, Slider slider)
|
||||
{
|
||||
//Instances.Add(this);
|
||||
|
||||
this.m_scrollbar = scrollbar;
|
||||
this.m_slider = slider;
|
||||
this.m_scrollRect = scrollbar.transform.parent.GetComponent<RectTransform>();
|
||||
@ -50,17 +48,6 @@ namespace UnityExplorer.UI.Utility
|
||||
this.m_slider.Set(1f, false);
|
||||
}
|
||||
|
||||
//internal bool CheckDestroyed()
|
||||
//{
|
||||
// if (!m_slider || !m_scrollbar)
|
||||
// {
|
||||
// Instances.Remove(this);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// return false;
|
||||
//}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
this.RefreshVisibility();
|
||||
@ -75,12 +62,12 @@ namespace UnityExplorer.UI.Utility
|
||||
}
|
||||
|
||||
bool shouldShow = !Mathf.Approximately(this.m_scrollbar.size, 1);
|
||||
var obj = this.m_slider.handleRect.gameObject;
|
||||
//var obj = this.m_slider.handleRect.gameObject;
|
||||
|
||||
if (IsActive != shouldShow)
|
||||
{
|
||||
IsActive = shouldShow;
|
||||
obj.SetActive(IsActive);
|
||||
m_slider.interactable = shouldShow;
|
||||
|
||||
if (IsActive)
|
||||
this.m_slider.Set(this.m_scrollbar.value, false);
|
||||
@ -109,14 +96,12 @@ namespace UnityExplorer.UI.Utility
|
||||
GameObject sliderObj = UIFactory.CreateUIObject("SliderScrollbar", parent, UIFactory._smallElementSize);
|
||||
|
||||
GameObject bgObj = UIFactory.CreateUIObject("Background", sliderObj);
|
||||
//GameObject fillAreaObj = UIFactory.CreateUIObject("Fill Area", sliderObj);
|
||||
//GameObject fillObj = UIFactory.CreateUIObject("Fill", fillAreaObj);
|
||||
GameObject handleSlideAreaObj = UIFactory.CreateUIObject("Handle Slide Area", sliderObj);
|
||||
GameObject handleObj = UIFactory.CreateUIObject("Handle", handleSlideAreaObj);
|
||||
|
||||
Image bgImage = bgObj.AddComponent<Image>();
|
||||
bgImage.type = Image.Type.Sliced;
|
||||
bgImage.color = new Color(0.05f, 0.05f, 0.05f, 1.0f);
|
||||
bgImage.color = new Color(0.1f, 0.1f, 0.1f, 1.0f);
|
||||
|
||||
RectTransform bgRect = bgObj.GetComponent<RectTransform>();
|
||||
bgRect.anchorMin = Vector2.zero;
|
||||
@ -128,7 +113,7 @@ namespace UnityExplorer.UI.Utility
|
||||
handleSlideRect.anchorMin = new Vector2(0f, 0f);
|
||||
handleSlideRect.anchorMax = new Vector2(1f, 1f);
|
||||
handleSlideRect.pivot = new Vector2(0.5f, 0.5f);
|
||||
handleSlideRect.offsetMin = new Vector2(27f, 30f);
|
||||
handleSlideRect.offsetMin = new Vector2(25f, 30f);
|
||||
handleSlideRect.offsetMax = new Vector2(-15f, 0f);
|
||||
handleSlideRect.sizeDelta = new Vector2(-20f, -30f);
|
||||
|
||||
@ -147,14 +132,14 @@ namespace UnityExplorer.UI.Utility
|
||||
sliderBarLayout.flexibleHeight = 5000;
|
||||
|
||||
slider = sliderObj.AddComponent<Slider>();
|
||||
//slider.fillRect = fillObj.GetComponent<RectTransform>();
|
||||
slider.handleRect = handleObj.GetComponent<RectTransform>();
|
||||
slider.targetGraphic = handleImage;
|
||||
slider.direction = Slider.Direction.BottomToTop;
|
||||
|
||||
RuntimeProvider.Instance.SetColorBlock(slider,
|
||||
new Color(0.25f, 0.25f, 0.25f),
|
||||
new Color(0.3f, 0.3f, 0.3f),
|
||||
RuntimeProvider.Instance.SetColorBlock(slider,
|
||||
new Color(0.4f, 0.4f, 0.4f),
|
||||
new Color(0.5f, 0.5f, 0.5f),
|
||||
new Color(0.3f, 0.3f, 0.3f),
|
||||
new Color(0.2f, 0.2f, 0.2f));
|
||||
|
||||
return sliderObj;
|
||||
|
Reference in New Issue
Block a user