mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-06-24 01:12:41 +08:00
More progress
This commit is contained in:
138
src/UI/Widgets/AutoSliderScrollbar.cs
Normal file
138
src/UI/Widgets/AutoSliderScrollbar.cs
Normal file
@ -0,0 +1,138 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer;
|
||||
using UnityExplorer.Core;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Models;
|
||||
|
||||
namespace UnityExplorer.UI.Utility
|
||||
{
|
||||
// A Slider Scrollbar which automatically resizes for the content size (no pooling).
|
||||
// Currently just used for the C# Console input field.
|
||||
|
||||
public class AutoSliderScrollbar : UIBehaviourModel
|
||||
{
|
||||
public override GameObject UIRoot
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Slider)
|
||||
return Slider.gameObject;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//public event Action<float> OnValueChanged;
|
||||
|
||||
internal readonly Scrollbar Scrollbar;
|
||||
internal readonly Slider Slider;
|
||||
internal RectTransform ContentRect;
|
||||
internal RectTransform ViewportRect;
|
||||
|
||||
//internal InputFieldScroller m_parentInputScroller;
|
||||
|
||||
public AutoSliderScrollbar(Scrollbar scrollbar, Slider slider, RectTransform contentRect, RectTransform viewportRect)
|
||||
{
|
||||
this.Scrollbar = scrollbar;
|
||||
this.Slider = slider;
|
||||
this.ContentRect = contentRect;
|
||||
this.ViewportRect = viewportRect;
|
||||
|
||||
this.Scrollbar.onValueChanged.AddListener(this.OnScrollbarValueChanged);
|
||||
this.Slider.onValueChanged.AddListener(this.OnSliderValueChanged);
|
||||
|
||||
//this.RefreshVisibility();
|
||||
this.Slider.Set(0f, false);
|
||||
}
|
||||
|
||||
private float lastAnchorPosition;
|
||||
private float lastContentHeight;
|
||||
private float lastViewportHeight;
|
||||
private bool _refreshWanted;
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (!Enabled)
|
||||
return;
|
||||
|
||||
_refreshWanted = false;
|
||||
if (ContentRect.localPosition.y != lastAnchorPosition)
|
||||
{
|
||||
lastAnchorPosition = ContentRect.localPosition.y;
|
||||
_refreshWanted = true;
|
||||
}
|
||||
if (ContentRect.rect.height != lastContentHeight)
|
||||
{
|
||||
lastContentHeight = ContentRect.rect.height;
|
||||
_refreshWanted = true;
|
||||
}
|
||||
if (ViewportRect.rect.height != lastViewportHeight)
|
||||
{
|
||||
lastViewportHeight = ViewportRect.rect.height;
|
||||
_refreshWanted = true;
|
||||
}
|
||||
|
||||
if (_refreshWanted)
|
||||
UpdateSliderHandle();
|
||||
}
|
||||
|
||||
public void UpdateSliderHandle()
|
||||
{
|
||||
// calculate handle size based on viewport / total data height
|
||||
var totalHeight = ContentRect.rect.height;
|
||||
var viewportHeight = ViewportRect.rect.height;
|
||||
|
||||
if (totalHeight <= viewportHeight)
|
||||
{
|
||||
Slider.value = 0f;
|
||||
Slider.interactable = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var handleHeight = viewportHeight * Math.Min(1, viewportHeight / totalHeight);
|
||||
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 (totalHeight > 0f)
|
||||
val = (float)((decimal)ContentRect.localPosition.y / (decimal)(totalHeight - ViewportRect.rect.height));
|
||||
|
||||
Slider.value = val;
|
||||
}
|
||||
|
||||
public void OnScrollbarValueChanged(float value)
|
||||
{
|
||||
value = 1f - value;
|
||||
if (this.Slider.value != value)
|
||||
this.Slider.Set(value, false);
|
||||
//OnValueChanged?.Invoke(value);
|
||||
}
|
||||
|
||||
public void OnSliderValueChanged(float value)
|
||||
{
|
||||
value = 1f - value;
|
||||
this.Scrollbar.value = value;
|
||||
//OnValueChanged?.Invoke(value);
|
||||
}
|
||||
|
||||
public override void ConstructUI(GameObject parent)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -19,106 +19,93 @@ namespace UnityExplorer.UI.Utility
|
||||
{
|
||||
get
|
||||
{
|
||||
if (inputField)
|
||||
return inputField.gameObject;
|
||||
if (InputField)
|
||||
return InputField.gameObject;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
internal SliderScrollbar sliderScroller;
|
||||
internal InputField inputField;
|
||||
internal AutoSliderScrollbar Slider;
|
||||
internal InputField InputField;
|
||||
|
||||
internal RectTransform inputRect;
|
||||
internal LayoutElement layoutElement;
|
||||
internal VerticalLayoutGroup parentLayoutGroup;
|
||||
internal RectTransform ContentRect;
|
||||
internal RectTransform ViewportRect;
|
||||
|
||||
internal static CanvasScaler canvasScaler;
|
||||
internal static CanvasScaler RootScaler;
|
||||
|
||||
public InputFieldScroller(SliderScrollbar sliderScroller, InputField inputField)
|
||||
public InputFieldScroller(AutoSliderScrollbar sliderScroller, InputField inputField)
|
||||
{
|
||||
//Instances.Add(this);
|
||||
|
||||
this.sliderScroller = sliderScroller;
|
||||
this.inputField = inputField;
|
||||
|
||||
sliderScroller.m_parentInputScroller = this;
|
||||
this.Slider = sliderScroller;
|
||||
this.InputField = inputField;
|
||||
|
||||
inputField.onValueChanged.AddListener(OnTextChanged);
|
||||
|
||||
inputRect = inputField.GetComponent<RectTransform>();
|
||||
layoutElement = inputField.gameObject.AddComponent<LayoutElement>();
|
||||
parentLayoutGroup = inputField.transform.parent.GetComponent<VerticalLayoutGroup>();
|
||||
ContentRect = inputField.GetComponent<RectTransform>();
|
||||
ViewportRect = ContentRect.transform.parent.GetComponent<RectTransform>();
|
||||
|
||||
layoutElement.minHeight = 25;
|
||||
layoutElement.minWidth = 100;
|
||||
|
||||
if (!canvasScaler)
|
||||
canvasScaler = UIManager.CanvasRoot.GetComponent<CanvasScaler>();
|
||||
if (!RootScaler)
|
||||
RootScaler = UIManager.CanvasRoot.GetComponent<CanvasScaler>();
|
||||
}
|
||||
|
||||
internal string m_lastText;
|
||||
internal bool m_updateWanted;
|
||||
|
||||
// only done once, to fix height on creation.
|
||||
internal bool heightInitAfterLayout;
|
||||
internal bool m_wantJumpToBottom;
|
||||
private float m_desiredContentHeight;
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (!heightInitAfterLayout)
|
||||
{
|
||||
heightInitAfterLayout = true;
|
||||
var height = sliderScroller.m_scrollRect.parent.parent.GetComponent<RectTransform>().rect.height;
|
||||
layoutElement.preferredHeight = height;
|
||||
}
|
||||
|
||||
if (m_updateWanted && inputField.gameObject.activeInHierarchy)
|
||||
if (m_updateWanted)
|
||||
{
|
||||
m_updateWanted = false;
|
||||
RefreshUI();
|
||||
ProcessInputText();
|
||||
}
|
||||
|
||||
float desiredHeight = Math.Max(m_desiredContentHeight, ViewportRect.rect.height);
|
||||
|
||||
if (ContentRect.rect.height < desiredHeight)
|
||||
{
|
||||
ContentRect.sizeDelta = new Vector2(0, desiredHeight);
|
||||
this.Slider.UpdateSliderHandle();
|
||||
}
|
||||
else if (ContentRect.rect.height > desiredHeight)
|
||||
{
|
||||
ContentRect.sizeDelta = new Vector2(0, desiredHeight);
|
||||
this.Slider.UpdateSliderHandle();
|
||||
}
|
||||
|
||||
if (m_wantJumpToBottom)
|
||||
{
|
||||
Slider.Slider.value = 1f;
|
||||
m_wantJumpToBottom = false;
|
||||
}
|
||||
}
|
||||
|
||||
//internal bool CheckDestroyed()
|
||||
//{
|
||||
// if (sliderScroller == null || sliderScroller.CheckDestroyed())
|
||||
// {
|
||||
// Instances.Remove(this);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// return false;
|
||||
//}
|
||||
|
||||
internal void OnTextChanged(string text)
|
||||
{
|
||||
m_lastText = text;
|
||||
m_updateWanted = true;
|
||||
}
|
||||
|
||||
internal void RefreshUI()
|
||||
internal void ProcessInputText()
|
||||
{
|
||||
var curInputRect = inputField.textComponent.rectTransform.rect;
|
||||
var scaleFactor = canvasScaler.scaleFactor;
|
||||
var curInputRect = InputField.textComponent.rectTransform.rect;
|
||||
var scaleFactor = RootScaler.scaleFactor;
|
||||
|
||||
// Current text settings
|
||||
var texGenSettings = inputField.textComponent.GetGenerationSettings(curInputRect.size);
|
||||
var texGenSettings = InputField.textComponent.GetGenerationSettings(curInputRect.size);
|
||||
texGenSettings.generateOutOfBounds = false;
|
||||
texGenSettings.scaleFactor = scaleFactor;
|
||||
|
||||
// Preferred text rect height
|
||||
var textGen = inputField.textComponent.cachedTextGeneratorForLayout;
|
||||
float preferredHeight = textGen.GetPreferredHeight(m_lastText, texGenSettings) + 10;
|
||||
var textGen = InputField.textComponent.cachedTextGeneratorForLayout;
|
||||
m_desiredContentHeight = textGen.GetPreferredHeight(m_lastText, texGenSettings) + 10;
|
||||
|
||||
// Default text rect height (fit to scroll parent or expand to fit text)
|
||||
float minHeight = Mathf.Max(preferredHeight, sliderScroller.m_scrollRect.rect.height - 25);
|
||||
|
||||
layoutElement.preferredHeight = minHeight;
|
||||
|
||||
if (inputField.caretPosition == inputField.text.Length
|
||||
&& inputField.text.Length > 0
|
||||
&& inputField.text[inputField.text.Length - 1] == '\n')
|
||||
// jump to bottom
|
||||
if (InputField.caretPosition == InputField.text.Length
|
||||
&& InputField.text.Length > 0
|
||||
&& InputField.text[InputField.text.Length - 1] == '\n')
|
||||
{
|
||||
sliderScroller.m_slider.value = 0f;
|
||||
m_wantJumpToBottom = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
// our first cell and they take priority, so reduce our height by
|
||||
// (minHeight - remainder) to account for that. We need to fill that
|
||||
// gap and reach the next cell before we take priority.
|
||||
if (!Mathf.Approximately(rem, 0f))
|
||||
if (rem != 0.0f)
|
||||
height -= (DefaultHeight - rem);
|
||||
|
||||
return (int)Math.Ceiling((decimal)height / (decimal)DefaultHeight);
|
||||
@ -139,8 +139,11 @@ namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
if (dataIndex >= ScrollPool.DataSource.ItemCount)
|
||||
{
|
||||
while (heightCache.Count > dataIndex)
|
||||
RemoveLast();
|
||||
if (heightCache.Count > dataIndex)
|
||||
{
|
||||
while (heightCache.Count > dataIndex)
|
||||
RemoveLast();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -249,14 +252,6 @@ namespace UnityExplorer.UI.Widgets
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//// if sister cache is set, then update it too.
|
||||
//if (SisterCache != null)
|
||||
//{
|
||||
// var realIdx = ScrollPool.DataSource.GetRealIndexOfTempIndex(dataIndex);
|
||||
// if (realIdx >= 0)
|
||||
// SisterCache.SetIndex(realIdx, height, true);
|
||||
//}
|
||||
}
|
||||
|
||||
private void RebuildCache()
|
||||
|
@ -115,7 +115,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
if (writingLocked && timeofLastWriteLock < Time.time)
|
||||
writingLocked = false;
|
||||
|
||||
if (prevContentHeight <= 1f && Content?.rect.height > 1f)
|
||||
if (prevContentHeight <= 1f && Content.rect.height > 1f)
|
||||
{
|
||||
prevContentHeight = Content.rect.height;
|
||||
}
|
||||
@ -131,10 +131,12 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
public void Rebuild()
|
||||
{
|
||||
HeightCache = new DataHeightCache<T>(this);
|
||||
|
||||
SetRecycleViewBounds(false);
|
||||
SetScrollBounds();
|
||||
|
||||
ExtendCellPool();
|
||||
CheckExtendCellPool();
|
||||
writingLocked = false;
|
||||
Content.anchoredPosition = Vector2.zero;
|
||||
UpdateSliderHandle(true);
|
||||
@ -163,6 +165,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
// Initialize
|
||||
|
||||
private bool m_doneFirstInit;
|
||||
private bool m_initialized;
|
||||
|
||||
public void Initialize(IPoolDataSource<T> dataSource)
|
||||
@ -173,12 +176,16 @@ namespace UnityExplorer.UI.Widgets
|
||||
HeightCache = new DataHeightCache<T>(this);
|
||||
DataSource = dataSource;
|
||||
|
||||
this.contentLayout = ScrollRect.content.GetComponent<VerticalLayoutGroup>();
|
||||
this.slider = ScrollRect.GetComponentInChildren<Slider>();
|
||||
slider.onValueChanged.AddListener(OnSliderValueChanged);
|
||||
if (!m_doneFirstInit)
|
||||
{
|
||||
m_doneFirstInit = true;
|
||||
this.contentLayout = ScrollRect.content.GetComponent<VerticalLayoutGroup>();
|
||||
this.slider = ScrollRect.GetComponentInChildren<Slider>();
|
||||
slider.onValueChanged.AddListener(OnSliderValueChanged);
|
||||
|
||||
ScrollRect.vertical = true;
|
||||
ScrollRect.horizontal = false;
|
||||
ScrollRect.vertical = true;
|
||||
ScrollRect.horizontal = false;
|
||||
}
|
||||
|
||||
ScrollRect.onValueChanged.RemoveListener(OnValueChangedListener);
|
||||
RuntimeProvider.Instance.StartCoroutine(InitCoroutine());
|
||||
@ -224,12 +231,18 @@ namespace UnityExplorer.UI.Widgets
|
||||
}
|
||||
CellPool.Clear();
|
||||
}
|
||||
|
||||
bottomDataIndex = -1;
|
||||
topPoolIndex = 0;
|
||||
bottomPoolIndex = 0;
|
||||
}
|
||||
|
||||
private void CreateCellPool(bool andResetDataIndex = true)
|
||||
private void CreateCellPool()
|
||||
{
|
||||
ReturnCells();
|
||||
|
||||
CheckDataSourceCountChange(out _);
|
||||
|
||||
float currentPoolCoverage = 0f;
|
||||
float requiredCoverage = ScrollRect.viewport.rect.height + RecycleThreshold;
|
||||
|
||||
@ -250,8 +263,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
currentPoolCoverage += PrototypeHeight;
|
||||
}
|
||||
|
||||
if (andResetDataIndex)
|
||||
bottomDataIndex = CellPool.Count - 1;
|
||||
bottomDataIndex = CellPool.Count - 1;
|
||||
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
||||
|
||||
@ -266,13 +278,12 @@ namespace UnityExplorer.UI.Widgets
|
||||
RecycleViewBounds = new Vector2(Viewport.MinY() + HalfThreshold, Viewport.MaxY() - HalfThreshold);
|
||||
|
||||
if (extendPoolIfGrown && prevViewportHeight < Viewport.rect.height && prevViewportHeight != 0.0f)
|
||||
ExtendCellPool();
|
||||
CheckExtendCellPool();
|
||||
|
||||
prevViewportHeight = Viewport.rect.height;
|
||||
|
||||
}
|
||||
|
||||
private bool ExtendCellPool()
|
||||
private bool CheckExtendCellPool()
|
||||
{
|
||||
CheckDataSourceCountChange(out _);
|
||||
|
||||
@ -285,6 +296,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
bottomDataIndex += cellsRequired;
|
||||
|
||||
// TODO sometimes still jumps a litte bit, need to figure out why.
|
||||
float prevAnchor = Content.localPosition.y;
|
||||
float prevHeight = Content.rect.height;
|
||||
|
||||
@ -299,21 +311,29 @@ namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
int index = CellPool.Count - 1 - (topPoolIndex % (CellPool.Count - 1));
|
||||
cell.Rect.SetSiblingIndex(index);
|
||||
|
||||
if (bottomPoolIndex == index - 1)
|
||||
bottomPoolIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
RefreshCells(true);
|
||||
|
||||
//ExplorerCore.Log("Anchor: " + Content.localPosition.y + ", prev: " + prevAnchor);
|
||||
//ExplorerCore.Log("Height: " + Content.rect.height + ", prev:" + prevHeight);
|
||||
|
||||
if (Content.localPosition.y != prevAnchor)
|
||||
{
|
||||
var diff = Content.localPosition.y - prevAnchor;
|
||||
Content.localPosition = new Vector3(Content.localPosition.x, Content.localPosition.y - diff);
|
||||
}
|
||||
|
||||
ScrollRect.UpdatePrevData();
|
||||
|
||||
SetScrollBounds();
|
||||
UpdateSliderHandle(true);
|
||||
if (Content.rect.height != prevHeight)
|
||||
{
|
||||
var diff = Content.rect.height - prevHeight;
|
||||
//ExplorerCore.Log("Height diff: " + diff);
|
||||
//Content.localPosition = new Vector3(Content.localPosition.x, Content.localPosition.y - diff);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -413,6 +433,16 @@ namespace UnityExplorer.UI.Widgets
|
||||
ScrollRect.UpdatePrevData();
|
||||
}
|
||||
|
||||
private void RefreshCellHeightsFast()
|
||||
{
|
||||
var enumerator = GetPoolEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
var curr = enumerator.Current;
|
||||
HeightCache.SetIndex(curr.dataIndex, CellPool[curr.cellIndex].Rect.rect.height);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetCell(T cachedCell, int dataIndex)
|
||||
{
|
||||
cachedCell.Enable();
|
||||
@ -432,6 +462,8 @@ namespace UnityExplorer.UI.Widgets
|
||||
if (InputManager.MouseScrollDelta != Vector2.zero)
|
||||
ScrollRect.StopMovement();
|
||||
|
||||
RefreshCellHeightsFast();
|
||||
|
||||
SetRecycleViewBounds(true);
|
||||
|
||||
float yChange = ((Vector2)ScrollRect.content.localPosition - prevAnchoredPos).y;
|
||||
@ -458,7 +490,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
SetScrollBounds();
|
||||
|
||||
//WritingLocked = true;
|
||||
UpdateSliderHandle();
|
||||
UpdateSliderHandle(true);
|
||||
}
|
||||
|
||||
private bool ShouldRecycleTop => GetCellExtent(CellPool[topPoolIndex].Rect) > RecycleViewBounds.x
|
||||
@ -598,6 +630,8 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
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;
|
||||
@ -630,52 +664,49 @@ namespace UnityExplorer.UI.Widgets
|
||||
// check if our pool indices contain the desired index. If so, rotate and set
|
||||
if (bottomDataIndex == desiredBottomIndex)
|
||||
{
|
||||
// cells will be the same, do nothing?
|
||||
// cells will be the same, do nothing
|
||||
}
|
||||
else if (TopDataIndex > poolStartIndex && TopDataIndex < desiredBottomIndex)
|
||||
{
|
||||
// top cell falls within the new range, rotate around that
|
||||
int rotate = TopDataIndex - poolStartIndex;
|
||||
for (int i = 0; i < rotate; i++)
|
||||
{
|
||||
CellPool[bottomPoolIndex].Rect.SetAsFirstSibling();
|
||||
|
||||
//set new indices
|
||||
topPoolIndex = bottomPoolIndex;
|
||||
bottomPoolIndex = (bottomPoolIndex - 1 + CellPool.Count) % CellPool.Count;
|
||||
bottomDataIndex--;
|
||||
|
||||
SetCell(CellPool[topPoolIndex], TopDataIndex);
|
||||
}
|
||||
}
|
||||
else if (bottomDataIndex > poolStartIndex && bottomDataIndex < desiredBottomIndex)
|
||||
{
|
||||
// bottom cells falls within the new range, rotate around that
|
||||
int rotate = desiredBottomIndex - bottomDataIndex;
|
||||
for (int i = 0; i < rotate; i++)
|
||||
{
|
||||
CellPool[topPoolIndex].Rect.SetAsLastSibling();
|
||||
|
||||
//set new indices
|
||||
bottomPoolIndex = topPoolIndex;
|
||||
topPoolIndex = (topPoolIndex + 1) % CellPool.Count;
|
||||
bottomDataIndex++;
|
||||
|
||||
SetCell(CellPool[bottomPoolIndex], bottomDataIndex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TopDataIndex > poolStartIndex && TopDataIndex < desiredBottomIndex)
|
||||
bottomDataIndex = desiredBottomIndex;
|
||||
var enumerator = GetPoolEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
// top cell falls within the new range, rotate around that
|
||||
int rotate = TopDataIndex - poolStartIndex;
|
||||
for (int i = 0; i < rotate; i++)
|
||||
{
|
||||
CellPool[bottomPoolIndex].Rect.SetAsFirstSibling();
|
||||
|
||||
//set new indices
|
||||
topPoolIndex = bottomPoolIndex;
|
||||
bottomPoolIndex = (bottomPoolIndex - 1 + CellPool.Count) % CellPool.Count;
|
||||
bottomDataIndex--;
|
||||
|
||||
SetCell(CellPool[topPoolIndex], TopDataIndex);
|
||||
}
|
||||
}
|
||||
else if (bottomDataIndex > poolStartIndex && bottomDataIndex < desiredBottomIndex)
|
||||
{
|
||||
// bottom cells falls within the new range, rotate around that
|
||||
int rotate = desiredBottomIndex - bottomDataIndex;
|
||||
for (int i = 0; i < rotate; i++)
|
||||
{
|
||||
CellPool[topPoolIndex].Rect.SetAsLastSibling();
|
||||
|
||||
//set new indices
|
||||
bottomPoolIndex = topPoolIndex;
|
||||
topPoolIndex = (topPoolIndex + 1) % CellPool.Count;
|
||||
bottomDataIndex++;
|
||||
|
||||
SetCell(CellPool[bottomPoolIndex], bottomDataIndex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bottomDataIndex = desiredBottomIndex;
|
||||
var enumerator = GetPoolEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
var curr = enumerator.Current;
|
||||
var cell = CellPool[curr.cellIndex];
|
||||
SetCell(cell, curr.dataIndex);
|
||||
}
|
||||
var curr = enumerator.Current;
|
||||
var cell = CellPool[curr.cellIndex];
|
||||
SetCell(cell, curr.dataIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,155 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer;
|
||||
using UnityExplorer.Core;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Models;
|
||||
|
||||
namespace UnityExplorer.UI.Utility
|
||||
{
|
||||
// Basically just to fix an issue with Scrollbars, instead we use a Slider as the scrollbar.
|
||||
public class SliderScrollbar : UIBehaviourModel
|
||||
{
|
||||
public bool IsActive { get; private set; }
|
||||
|
||||
public override GameObject UIRoot
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_slider)
|
||||
return m_slider.gameObject;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public event Action<float> OnValueChanged;
|
||||
|
||||
internal readonly Scrollbar m_scrollbar;
|
||||
internal readonly Slider m_slider;
|
||||
internal readonly RectTransform m_scrollRect;
|
||||
|
||||
internal InputFieldScroller m_parentInputScroller;
|
||||
|
||||
public SliderScrollbar(Scrollbar scrollbar, Slider slider)
|
||||
{
|
||||
this.m_scrollbar = scrollbar;
|
||||
this.m_slider = slider;
|
||||
this.m_scrollRect = scrollbar.transform.parent.GetComponent<RectTransform>();
|
||||
|
||||
this.m_scrollbar.onValueChanged.AddListener(this.OnScrollbarValueChanged);
|
||||
this.m_slider.onValueChanged.AddListener(this.OnSliderValueChanged);
|
||||
|
||||
this.RefreshVisibility();
|
||||
this.m_slider.Set(1f, false);
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
this.RefreshVisibility();
|
||||
}
|
||||
|
||||
internal void RefreshVisibility()
|
||||
{
|
||||
if (!m_slider.gameObject.activeInHierarchy)
|
||||
{
|
||||
IsActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
bool shouldShow = !Mathf.Approximately(this.m_scrollbar.size, 1);
|
||||
//var obj = this.m_slider.handleRect.gameObject;
|
||||
|
||||
if (IsActive != shouldShow)
|
||||
{
|
||||
IsActive = shouldShow;
|
||||
m_slider.interactable = shouldShow;
|
||||
|
||||
if (IsActive)
|
||||
this.m_slider.Set(this.m_scrollbar.value, false);
|
||||
else
|
||||
m_slider.Set(1f, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnScrollbarValueChanged(float _value)
|
||||
{
|
||||
if (this.m_slider.value != _value)
|
||||
this.m_slider.Set(_value, false);
|
||||
OnValueChanged?.Invoke(_value);
|
||||
}
|
||||
|
||||
public void OnSliderValueChanged(float _value)
|
||||
{
|
||||
this.m_scrollbar.value = _value;
|
||||
OnValueChanged?.Invoke(_value);
|
||||
}
|
||||
|
||||
#region UI CONSTRUCTION
|
||||
|
||||
public static GameObject CreateSliderScrollbar(GameObject parent, out Slider slider)
|
||||
{
|
||||
GameObject sliderObj = UIFactory.CreateUIObject("SliderScrollbar", parent, UIFactory._smallElementSize);
|
||||
|
||||
GameObject bgObj = UIFactory.CreateUIObject("Background", sliderObj);
|
||||
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.1f, 0.1f, 0.1f, 1.0f);
|
||||
|
||||
RectTransform bgRect = bgObj.GetComponent<RectTransform>();
|
||||
bgRect.anchorMin = Vector2.zero;
|
||||
bgRect.anchorMax = Vector2.one;
|
||||
bgRect.sizeDelta = Vector2.zero;
|
||||
bgRect.offsetMax = new Vector2(0f, 0f);
|
||||
|
||||
RectTransform handleSlideRect = handleSlideAreaObj.GetComponent<RectTransform>();
|
||||
handleSlideRect.anchorMin = new Vector2(0f, 0f);
|
||||
handleSlideRect.anchorMax = new Vector2(1f, 1f);
|
||||
handleSlideRect.pivot = new Vector2(0.5f, 0.5f);
|
||||
handleSlideRect.offsetMin = new Vector2(25f, 30f);
|
||||
handleSlideRect.offsetMax = new Vector2(-15f, 0f);
|
||||
handleSlideRect.sizeDelta = new Vector2(-20f, -30f);
|
||||
|
||||
Image handleImage = handleObj.AddComponent<Image>();
|
||||
handleImage.color = new Color(0.5f, 0.5f, 0.5f, 1.0f);
|
||||
|
||||
var handleRect = handleObj.GetComponent<RectTransform>();
|
||||
handleRect.sizeDelta = new Vector2(15f, 30f);
|
||||
handleRect.offsetMin = new Vector2(-13f, -28f);
|
||||
handleRect.offsetMax = new Vector2(2f, -2f);
|
||||
|
||||
var sliderBarLayout = sliderObj.AddComponent<LayoutElement>();
|
||||
sliderBarLayout.minWidth = 25;
|
||||
sliderBarLayout.flexibleWidth = 0;
|
||||
sliderBarLayout.minHeight = 30;
|
||||
sliderBarLayout.flexibleHeight = 5000;
|
||||
|
||||
slider = sliderObj.AddComponent<Slider>();
|
||||
slider.handleRect = handleObj.GetComponent<RectTransform>();
|
||||
slider.targetGraphic = handleImage;
|
||||
slider.direction = Slider.Direction.BottomToTop;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public override void ConstructUI(GameObject parent)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user