1023 lines
23 KiB
C#
1023 lines
23 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using EasyLayout;
|
|
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.Events;
|
|
using UnityEngine.Serialization;
|
|
using UnityEngine.UI;
|
|
|
|
namespace UIWidgets
|
|
{
|
|
public class ListViewCustom<TComponent, TItem> : ListViewBase where TComponent : ListViewItem
|
|
{
|
|
[SerializeField]
|
|
protected List<TItem> customItems = new List<TItem>();
|
|
|
|
public ObservableList<TItem> dataSource;
|
|
|
|
[SerializeField]
|
|
public TComponent DefaultItem;
|
|
|
|
protected List<TComponent> components = new List<TComponent>();
|
|
|
|
protected List<TComponent> componentsCache = new List<TComponent>();
|
|
|
|
private Dictionary<int, UnityAction<PointerEventData>> callbacksEnter = new Dictionary<int, UnityAction<PointerEventData>>();
|
|
|
|
private Dictionary<int, UnityAction<PointerEventData>> callbacksExit = new Dictionary<int, UnityAction<PointerEventData>>();
|
|
|
|
[SerializeField]
|
|
[FormerlySerializedAs("Sort")]
|
|
private bool sort = true;
|
|
|
|
private Func<IEnumerable<TItem>, IEnumerable<TItem>> sortFunc;
|
|
|
|
public ListViewCustomEvent OnSelectObject = new ListViewCustomEvent();
|
|
|
|
public ListViewCustomEvent OnDeselectObject = new ListViewCustomEvent();
|
|
|
|
public ListViewCustomEvent OnPointerEnterObject = new ListViewCustomEvent();
|
|
|
|
public ListViewCustomEvent OnPointerExitObject = new ListViewCustomEvent();
|
|
|
|
[SerializeField]
|
|
private Color defaultBackgroundColor = Color.white;
|
|
|
|
[SerializeField]
|
|
private Color defaultColor = Color.black;
|
|
|
|
[SerializeField]
|
|
public Color HighlightedBackgroundColor = new Color(203f, 230f, 244f, 255f);
|
|
|
|
[SerializeField]
|
|
public Color HighlightedColor = Color.black;
|
|
|
|
[SerializeField]
|
|
private Color selectedBackgroundColor = new Color(53f, 83f, 227f, 255f);
|
|
|
|
[SerializeField]
|
|
private Color selectedColor = Color.black;
|
|
|
|
[SerializeField]
|
|
protected ScrollRect scrollRect;
|
|
|
|
[Tooltip("Minimal height of item")]
|
|
[SerializeField]
|
|
protected float itemHeight;
|
|
|
|
[Tooltip("Minimal width of item")]
|
|
[SerializeField]
|
|
protected float itemWidth;
|
|
|
|
protected float scrollHeight;
|
|
|
|
protected float scrollWidth;
|
|
|
|
protected int maxVisibleItems;
|
|
|
|
protected int visibleItems;
|
|
|
|
protected int topHiddenItems;
|
|
|
|
protected int bottomHiddenItems;
|
|
|
|
[SerializeField]
|
|
private ListViewDirection direction = ListViewDirection.Vertical;
|
|
|
|
protected bool setContentSizeFitter = true;
|
|
|
|
[NonSerialized]
|
|
private bool isStartedListViewCustom;
|
|
|
|
protected LayoutGroup layout;
|
|
|
|
protected List<TItem> SelectedItemsCache;
|
|
|
|
protected ILayoutBridge LayoutBridge;
|
|
|
|
[SerializeField]
|
|
protected bool KeepSelection = true;
|
|
|
|
public UnityEvent OnStartScrolling = new UnityEvent();
|
|
|
|
public UnityEvent OnEndScrolling = new UnityEvent();
|
|
|
|
public float EndScrollDelay = 0.3f;
|
|
|
|
private bool scrolling;
|
|
|
|
private float lastScrollingTime;
|
|
|
|
private bool needResize;
|
|
|
|
public ObservableList<TItem> DataSource
|
|
{
|
|
get
|
|
{
|
|
if (dataSource == null)
|
|
{
|
|
dataSource = new ObservableList<TItem>(customItems);
|
|
dataSource.OnChange += UpdateItems;
|
|
customItems = null;
|
|
}
|
|
return dataSource;
|
|
}
|
|
set
|
|
{
|
|
SetNewItems(value);
|
|
SetScrollValue(0f);
|
|
}
|
|
}
|
|
|
|
[Obsolete("Use DataSource instead.")]
|
|
public new List<TItem> Items
|
|
{
|
|
get
|
|
{
|
|
return new List<TItem>(DataSource);
|
|
}
|
|
set
|
|
{
|
|
SetNewItems(new ObservableList<TItem>(value));
|
|
SetScrollValue(0f);
|
|
}
|
|
}
|
|
|
|
public TItem SelectedItem
|
|
{
|
|
get
|
|
{
|
|
if (base.SelectedIndex == -1)
|
|
{
|
|
return default(TItem);
|
|
}
|
|
return DataSource[base.SelectedIndex];
|
|
}
|
|
}
|
|
|
|
public List<TItem> SelectedItems
|
|
{
|
|
get
|
|
{
|
|
return base.SelectedIndicies.Convert(GetDataItem);
|
|
}
|
|
}
|
|
|
|
public bool Sort
|
|
{
|
|
get
|
|
{
|
|
return sort;
|
|
}
|
|
set
|
|
{
|
|
sort = value;
|
|
if (Sort && isStartedListViewCustom)
|
|
{
|
|
UpdateItems();
|
|
}
|
|
}
|
|
}
|
|
|
|
public Func<IEnumerable<TItem>, IEnumerable<TItem>> SortFunc
|
|
{
|
|
get
|
|
{
|
|
return sortFunc;
|
|
}
|
|
set
|
|
{
|
|
sortFunc = value;
|
|
if (Sort && isStartedListViewCustom)
|
|
{
|
|
UpdateItems();
|
|
}
|
|
}
|
|
}
|
|
|
|
public Color DefaultBackgroundColor
|
|
{
|
|
get
|
|
{
|
|
return defaultBackgroundColor;
|
|
}
|
|
set
|
|
{
|
|
defaultBackgroundColor = value;
|
|
UpdateColors();
|
|
}
|
|
}
|
|
|
|
public Color DefaultColor
|
|
{
|
|
get
|
|
{
|
|
return defaultColor;
|
|
}
|
|
set
|
|
{
|
|
DefaultColor = value;
|
|
UpdateColors();
|
|
}
|
|
}
|
|
|
|
public Color SelectedBackgroundColor
|
|
{
|
|
get
|
|
{
|
|
return selectedBackgroundColor;
|
|
}
|
|
set
|
|
{
|
|
selectedBackgroundColor = value;
|
|
UpdateColors();
|
|
}
|
|
}
|
|
|
|
public Color SelectedColor
|
|
{
|
|
get
|
|
{
|
|
return selectedColor;
|
|
}
|
|
set
|
|
{
|
|
selectedColor = value;
|
|
UpdateColors();
|
|
}
|
|
}
|
|
|
|
public ScrollRect ScrollRect
|
|
{
|
|
get
|
|
{
|
|
return scrollRect;
|
|
}
|
|
set
|
|
{
|
|
if (scrollRect != null)
|
|
{
|
|
ResizeListener component = scrollRect.GetComponent<ResizeListener>();
|
|
if (component != null)
|
|
{
|
|
component.OnResize.RemoveListener(SetNeedResize);
|
|
}
|
|
scrollRect.onValueChanged.RemoveListener(OnScrollRectUpdate);
|
|
}
|
|
scrollRect = value;
|
|
if (scrollRect != null)
|
|
{
|
|
ResizeListener resizeListener = scrollRect.GetComponent<ResizeListener>() ?? scrollRect.gameObject.AddComponent<ResizeListener>();
|
|
resizeListener.OnResize.AddListener(SetNeedResize);
|
|
scrollRect.onValueChanged.AddListener(OnScrollRectUpdate);
|
|
}
|
|
}
|
|
}
|
|
|
|
public ListViewDirection Direction
|
|
{
|
|
get
|
|
{
|
|
return direction;
|
|
}
|
|
set
|
|
{
|
|
direction = value;
|
|
if ((bool)scrollRect)
|
|
{
|
|
scrollRect.horizontal = IsHorizontal();
|
|
scrollRect.vertical = !IsHorizontal();
|
|
}
|
|
if (CanOptimize() && layout is global::EasyLayout.EasyLayout)
|
|
{
|
|
LayoutBridge.IsHorizontal = IsHorizontal();
|
|
if (isStartedListViewCustom)
|
|
{
|
|
CalculateMaxVisibleItems();
|
|
}
|
|
}
|
|
if (isStartedListViewCustom)
|
|
{
|
|
UpdateView();
|
|
}
|
|
}
|
|
}
|
|
|
|
public global::EasyLayout.EasyLayout Layout
|
|
{
|
|
get
|
|
{
|
|
return layout as global::EasyLayout.EasyLayout;
|
|
}
|
|
}
|
|
|
|
protected virtual void Awake()
|
|
{
|
|
Start();
|
|
}
|
|
|
|
public override void Start()
|
|
{
|
|
if (isStartedListViewCustom)
|
|
{
|
|
return;
|
|
}
|
|
base.Start();
|
|
base.Items = new List<ListViewItem>();
|
|
SelectedItemsCache = SelectedItems;
|
|
SetItemIndicies = false;
|
|
DestroyGameObjects = false;
|
|
if (DefaultItem == null)
|
|
{
|
|
throw new NullReferenceException(string.Format("DefaultItem is null. Set component of type {0} to DefaultItem.", typeof(TComponent).FullName));
|
|
}
|
|
DefaultItem.gameObject.SetActive(true);
|
|
if (CanOptimize())
|
|
{
|
|
ScrollRect = scrollRect;
|
|
RectTransform rectTransform = scrollRect.transform as RectTransform;
|
|
scrollHeight = rectTransform.rect.height;
|
|
scrollWidth = rectTransform.rect.width;
|
|
layout = Container.GetComponent<LayoutGroup>();
|
|
if (layout is global::EasyLayout.EasyLayout)
|
|
{
|
|
LayoutBridge = new EasyLayoutBridge(layout as global::EasyLayout.EasyLayout, DefaultItem.transform as RectTransform);
|
|
LayoutBridge.IsHorizontal = IsHorizontal();
|
|
}
|
|
else if (layout is HorizontalOrVerticalLayoutGroup)
|
|
{
|
|
LayoutBridge = new StandardLayoutBridge(layout as HorizontalOrVerticalLayoutGroup, DefaultItem.transform as RectTransform);
|
|
}
|
|
CalculateItemSize();
|
|
CalculateMaxVisibleItems();
|
|
ResizeListener resizeListener = scrollRect.gameObject.AddComponent<ResizeListener>();
|
|
resizeListener.OnResize.AddListener(SetNeedResize);
|
|
}
|
|
DefaultItem.gameObject.SetActive(false);
|
|
Direction = direction;
|
|
UpdateItems();
|
|
OnSelect.AddListener(OnSelectCallback);
|
|
OnDeselect.AddListener(OnDeselectCallback);
|
|
isStartedListViewCustom = true;
|
|
}
|
|
|
|
protected TItem GetDataItem(int index)
|
|
{
|
|
return DataSource[index];
|
|
}
|
|
|
|
protected virtual void CalculateItemSize()
|
|
{
|
|
if (LayoutBridge != null)
|
|
{
|
|
Vector2 itemSize = LayoutBridge.GetItemSize();
|
|
if (itemHeight == 0f)
|
|
{
|
|
itemHeight = itemSize.y;
|
|
}
|
|
if (itemWidth == 0f)
|
|
{
|
|
itemWidth = itemSize.x;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected bool IsHorizontal()
|
|
{
|
|
return direction == ListViewDirection.Horizontal;
|
|
}
|
|
|
|
protected virtual void CalculateMaxVisibleItems()
|
|
{
|
|
if (IsHorizontal())
|
|
{
|
|
maxVisibleItems = Mathf.CeilToInt(scrollWidth / itemWidth);
|
|
}
|
|
else
|
|
{
|
|
maxVisibleItems = Mathf.CeilToInt(scrollHeight / itemHeight);
|
|
}
|
|
maxVisibleItems = Mathf.Max(maxVisibleItems, 1) + 1;
|
|
}
|
|
|
|
public virtual void Resize()
|
|
{
|
|
needResize = false;
|
|
RectTransform rectTransform = scrollRect.transform as RectTransform;
|
|
scrollHeight = rectTransform.rect.height;
|
|
scrollWidth = rectTransform.rect.width;
|
|
itemHeight = 0f;
|
|
itemWidth = 0f;
|
|
CalculateItemSize();
|
|
CalculateMaxVisibleItems();
|
|
UpdateView();
|
|
components.Sort(ComponentsComparer);
|
|
components.ForEach(base.SetComponentAsLastSibling);
|
|
}
|
|
|
|
protected virtual bool CanOptimize()
|
|
{
|
|
bool flag = scrollRect != null;
|
|
LayoutGroup layoutGroup = ((!(Container != null)) ? null : (layout ?? Container.GetComponent<LayoutGroup>()));
|
|
bool flag2 = (bool)layoutGroup && (layoutGroup is global::EasyLayout.EasyLayout || layoutGroup is HorizontalOrVerticalLayoutGroup);
|
|
return flag && flag2;
|
|
}
|
|
|
|
private void OnSelectCallback(int index, ListViewItem item)
|
|
{
|
|
if (SelectedItemsCache != null)
|
|
{
|
|
SelectedItemsCache.Add(DataSource[index]);
|
|
}
|
|
OnSelectObject.Invoke(index);
|
|
if (item != null)
|
|
{
|
|
SelectColoring(item);
|
|
}
|
|
}
|
|
|
|
private void OnDeselectCallback(int index, ListViewItem item)
|
|
{
|
|
if (SelectedItemsCache != null)
|
|
{
|
|
SelectedItemsCache.Remove(DataSource[index]);
|
|
}
|
|
OnDeselectObject.Invoke(index);
|
|
if (item != null)
|
|
{
|
|
DefaultColoring(item);
|
|
}
|
|
}
|
|
|
|
private void OnPointerEnterCallback(ListViewItem item)
|
|
{
|
|
OnPointerEnterObject.Invoke(item.Index);
|
|
if (!IsSelected(item.Index))
|
|
{
|
|
HighlightColoring(item);
|
|
}
|
|
}
|
|
|
|
private void OnPointerExitCallback(ListViewItem item)
|
|
{
|
|
OnPointerExitObject.Invoke(item.Index);
|
|
if (!IsSelected(item.Index))
|
|
{
|
|
DefaultColoring(item);
|
|
}
|
|
}
|
|
|
|
public override void UpdateItems()
|
|
{
|
|
SetNewItems(DataSource);
|
|
}
|
|
|
|
public override void Clear()
|
|
{
|
|
DataSource.Clear();
|
|
SetScrollValue(0f);
|
|
}
|
|
|
|
public virtual int Add(TItem item)
|
|
{
|
|
if (item == null)
|
|
{
|
|
throw new ArgumentNullException("item", "Item is null.");
|
|
}
|
|
DataSource.Add(item);
|
|
return DataSource.IndexOf(item);
|
|
}
|
|
|
|
public virtual int Remove(TItem item)
|
|
{
|
|
int num = DataSource.IndexOf(item);
|
|
if (num == -1)
|
|
{
|
|
return num;
|
|
}
|
|
DataSource.RemoveAt(num);
|
|
return num;
|
|
}
|
|
|
|
public virtual void Remove(int index)
|
|
{
|
|
DataSource.RemoveAt(index);
|
|
}
|
|
|
|
protected void SetScrollValue(float value, bool callScrollUpdate = true)
|
|
{
|
|
if (scrollRect.content == null)
|
|
{
|
|
return;
|
|
}
|
|
Vector2 anchoredPosition = scrollRect.content.anchoredPosition;
|
|
Vector2 anchoredPosition2 = ((!IsHorizontal()) ? new Vector2(anchoredPosition.x, value) : new Vector2(value, anchoredPosition.y));
|
|
bool flag = IsHorizontal() && Mathf.Abs(anchoredPosition.x - anchoredPosition2.x) > 0.1f;
|
|
bool flag2 = !IsHorizontal() && Mathf.Abs(anchoredPosition.y - anchoredPosition2.y) > 0.1f;
|
|
if (flag || flag2)
|
|
{
|
|
scrollRect.content.anchoredPosition = anchoredPosition2;
|
|
if (callScrollUpdate)
|
|
{
|
|
ScrollUpdate();
|
|
}
|
|
}
|
|
}
|
|
|
|
protected float GetScrollValue()
|
|
{
|
|
Vector2 anchoredPosition = scrollRect.content.anchoredPosition;
|
|
return Mathf.Max(0f, (!IsHorizontal()) ? anchoredPosition.y : (0f - anchoredPosition.x));
|
|
}
|
|
|
|
protected override void ScrollTo(int index)
|
|
{
|
|
if (CanOptimize())
|
|
{
|
|
int firstVisibleIndex = GetFirstVisibleIndex(true);
|
|
int lastVisibleIndex = GetLastVisibleIndex(true);
|
|
if (firstVisibleIndex > index)
|
|
{
|
|
SetScrollValue(GetItemPosition(index));
|
|
}
|
|
else if (lastVisibleIndex < index)
|
|
{
|
|
SetScrollValue(GetItemPositionBottom(index));
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual float GetItemPosition(int index)
|
|
{
|
|
return (float)index * GetItemSize();
|
|
}
|
|
|
|
protected virtual float GetItemPositionBottom(int index)
|
|
{
|
|
return GetItemPosition(index) + GetItemSize() - LayoutBridge.GetSpacing() + LayoutBridge.GetMargin() - GetScrollSize();
|
|
}
|
|
|
|
protected void RemoveCallbacks()
|
|
{
|
|
base.Items.ForEach(RemoveCallback);
|
|
}
|
|
|
|
protected void AddCallbacks()
|
|
{
|
|
base.Items.ForEach(AddCallback);
|
|
}
|
|
|
|
protected virtual void RemoveCallback(ListViewItem item, int index)
|
|
{
|
|
if (callbacksEnter.ContainsKey(index))
|
|
{
|
|
if (item != null)
|
|
{
|
|
item.onPointerEnter.RemoveListener(callbacksEnter[index]);
|
|
}
|
|
callbacksEnter.Remove(index);
|
|
}
|
|
if (callbacksExit.ContainsKey(index))
|
|
{
|
|
if (item != null)
|
|
{
|
|
item.onPointerExit.RemoveListener(callbacksExit[index]);
|
|
}
|
|
callbacksExit.Remove(index);
|
|
}
|
|
}
|
|
|
|
protected virtual void AddCallback(ListViewItem item, int index)
|
|
{
|
|
callbacksEnter.Add(index, delegate
|
|
{
|
|
OnPointerEnterCallback(item);
|
|
});
|
|
callbacksExit.Add(index, delegate
|
|
{
|
|
OnPointerExitCallback(item);
|
|
});
|
|
item.onPointerEnter.AddListener(callbacksEnter[index]);
|
|
item.onPointerExit.AddListener(callbacksExit[index]);
|
|
}
|
|
|
|
public int Set(TItem item, bool allowDuplicate = true)
|
|
{
|
|
int num;
|
|
if (!allowDuplicate)
|
|
{
|
|
num = DataSource.IndexOf(item);
|
|
if (num == -1)
|
|
{
|
|
num = Add(item);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
num = Add(item);
|
|
}
|
|
Select(num);
|
|
return num;
|
|
}
|
|
|
|
protected virtual void SetData(TComponent component, TItem item)
|
|
{
|
|
}
|
|
|
|
protected void UpdateComponentsCount()
|
|
{
|
|
components.RemoveAll(IsNullComponent);
|
|
if (components.Count != visibleItems)
|
|
{
|
|
if (components.Count < visibleItems)
|
|
{
|
|
componentsCache.RemoveAll(IsNullComponent);
|
|
Enumerable.Range(0, visibleItems - components.Count).ForEach(AddComponent);
|
|
}
|
|
else
|
|
{
|
|
IOrderedEnumerable<TComponent> orderedEnumerable = components.GetRange(visibleItems, components.Count - visibleItems).OrderByDescending(base.GetComponentIndex);
|
|
orderedEnumerable.ForEach(DeactivateComponent);
|
|
componentsCache.AddRange(orderedEnumerable);
|
|
components.RemoveRange(visibleItems, components.Count - visibleItems);
|
|
}
|
|
base.Items = components.Convert((Converter<TComponent, ListViewItem>)((TComponent x) => x));
|
|
}
|
|
}
|
|
|
|
private bool IsNullComponent(TComponent component)
|
|
{
|
|
return component == null;
|
|
}
|
|
|
|
private void AddComponent(int index)
|
|
{
|
|
TComponent val;
|
|
if (componentsCache.Count > 0)
|
|
{
|
|
val = componentsCache[componentsCache.Count - 1];
|
|
componentsCache.RemoveAt(componentsCache.Count - 1);
|
|
}
|
|
else
|
|
{
|
|
val = UnityEngine.Object.Instantiate(DefaultItem);
|
|
Utilites.FixInstantiated(DefaultItem, val);
|
|
}
|
|
val.Index = -1;
|
|
val.transform.SetAsLastSibling();
|
|
val.gameObject.SetActive(true);
|
|
components.Add(val);
|
|
}
|
|
|
|
private void DeactivateComponent(TComponent component)
|
|
{
|
|
RemoveCallback(component, component.Index);
|
|
if (component != null)
|
|
{
|
|
component.MovedToCache();
|
|
component.Index = -1;
|
|
component.gameObject.SetActive(false);
|
|
}
|
|
}
|
|
|
|
protected float GetItemSize()
|
|
{
|
|
return (!IsHorizontal()) ? (itemHeight + LayoutBridge.GetSpacing()) : (itemWidth + LayoutBridge.GetSpacing());
|
|
}
|
|
|
|
protected float GetScrollSize()
|
|
{
|
|
return (!IsHorizontal()) ? scrollHeight : scrollWidth;
|
|
}
|
|
|
|
protected virtual int GetLastVisibleIndex(bool strict = false)
|
|
{
|
|
float num = GetScrollValue() + GetScrollSize();
|
|
int num2 = ((!strict) ? Mathf.CeilToInt(num / GetItemSize()) : Mathf.FloorToInt(num / GetItemSize()));
|
|
return num2 - 1;
|
|
}
|
|
|
|
protected virtual int GetFirstVisibleIndex(bool strict = false)
|
|
{
|
|
int b = ((!strict) ? Mathf.FloorToInt(GetScrollValue() / GetItemSize()) : Mathf.CeilToInt(GetScrollValue() / GetItemSize()));
|
|
b = Mathf.Max(0, b);
|
|
if (strict)
|
|
{
|
|
return b;
|
|
}
|
|
return Mathf.Min(b, Mathf.Max(0, DataSource.Count - visibleItems));
|
|
}
|
|
|
|
protected virtual void ScrollUpdate()
|
|
{
|
|
int num = topHiddenItems;
|
|
topHiddenItems = GetFirstVisibleIndex();
|
|
bottomHiddenItems = Mathf.Max(0, DataSource.Count - visibleItems - topHiddenItems);
|
|
if (num != topHiddenItems)
|
|
{
|
|
if (num == topHiddenItems + 1)
|
|
{
|
|
TComponent val = components[components.Count - 1];
|
|
components.RemoveAt(components.Count - 1);
|
|
components.Insert(0, val);
|
|
val.transform.SetAsFirstSibling();
|
|
val.Index = topHiddenItems;
|
|
SetData(val, DataSource[topHiddenItems]);
|
|
Coloring(val);
|
|
}
|
|
else if (num == topHiddenItems - 1)
|
|
{
|
|
TComponent val2 = components[0];
|
|
components.RemoveAt(0);
|
|
components.Add(val2);
|
|
val2.transform.SetAsLastSibling();
|
|
val2.Index = topHiddenItems + visibleItems - 1;
|
|
SetData(val2, DataSource[topHiddenItems + visibleItems - 1]);
|
|
Coloring(val2);
|
|
}
|
|
else
|
|
{
|
|
List<int> second = components.Convert(base.GetComponentIndex);
|
|
int[] new_visible_range = Enumerable.Range(topHiddenItems, visibleItems).ToArray();
|
|
List<int> list = new_visible_range.Except(second).ToList();
|
|
Stack<TComponent> components_to_change = new Stack<TComponent>(components.Where((TComponent x) => !new_visible_range.Contains(x.Index)));
|
|
list.ForEach(delegate(int index)
|
|
{
|
|
TComponent val3 = components_to_change.Pop();
|
|
val3.Index = index;
|
|
SetData(val3, DataSource[index]);
|
|
Coloring(val3);
|
|
});
|
|
components.Sort(ComponentsComparer);
|
|
components.ForEach(base.SetComponentAsLastSibling);
|
|
}
|
|
}
|
|
if (LayoutBridge != null)
|
|
{
|
|
LayoutBridge.SetFiller(CalculateTopFillerSize(), CalculateBottomFillerSize());
|
|
LayoutBridge.UpdateLayout();
|
|
}
|
|
}
|
|
|
|
protected int ComponentsComparer(TComponent x, TComponent y)
|
|
{
|
|
return x.Index.CompareTo(y.Index);
|
|
}
|
|
|
|
protected virtual void OnScrollRectUpdate(Vector2 position)
|
|
{
|
|
StartScrolling();
|
|
ScrollUpdate();
|
|
}
|
|
|
|
protected void UpdateView()
|
|
{
|
|
RemoveCallbacks();
|
|
if (CanOptimize() && DataSource.Count > 0)
|
|
{
|
|
visibleItems = ((maxVisibleItems >= DataSource.Count) ? DataSource.Count : maxVisibleItems);
|
|
}
|
|
else
|
|
{
|
|
visibleItems = DataSource.Count;
|
|
}
|
|
if (CanOptimize())
|
|
{
|
|
topHiddenItems = GetFirstVisibleIndex();
|
|
if (topHiddenItems > DataSource.Count - 1)
|
|
{
|
|
topHiddenItems = Mathf.Max(0, DataSource.Count - 2);
|
|
}
|
|
if (topHiddenItems + visibleItems > DataSource.Count)
|
|
{
|
|
visibleItems = DataSource.Count - topHiddenItems;
|
|
}
|
|
bottomHiddenItems = Mathf.Max(0, DataSource.Count - visibleItems - topHiddenItems);
|
|
}
|
|
else
|
|
{
|
|
topHiddenItems = 0;
|
|
bottomHiddenItems = DataSource.Count() - visibleItems;
|
|
}
|
|
UpdateComponentsCount();
|
|
int[] indicies = Enumerable.Range(topHiddenItems, visibleItems).ToArray();
|
|
components.ForEach(delegate(TComponent x, int i)
|
|
{
|
|
x.Index = indicies[i];
|
|
SetData(x, DataSource[indicies[i]]);
|
|
Coloring(x);
|
|
});
|
|
AddCallbacks();
|
|
if (LayoutBridge != null)
|
|
{
|
|
LayoutBridge.SetFiller(CalculateTopFillerSize(), CalculateBottomFillerSize());
|
|
LayoutBridge.UpdateLayout();
|
|
}
|
|
if (ScrollRect != null)
|
|
{
|
|
float num = ((DataSource.Count != 0) ? Mathf.Max(0f, GetItemPositionBottom(DataSource.Count - 1)) : 0f);
|
|
if (GetScrollValue() > num)
|
|
{
|
|
SetScrollValue(num);
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool IndexNotFound(int index)
|
|
{
|
|
return index == -1;
|
|
}
|
|
|
|
protected virtual void SetNewItems(ObservableList<TItem> newItems)
|
|
{
|
|
DataSource.OnChange -= UpdateItems;
|
|
if (Sort && SortFunc != null)
|
|
{
|
|
newItems.BeginUpdate();
|
|
TItem[] array = SortFunc(newItems).ToArray();
|
|
newItems.Clear();
|
|
newItems.AddRange(array);
|
|
newItems.EndUpdate();
|
|
}
|
|
SilentDeselect(base.SelectedIndicies);
|
|
List<int> list = SelectedItemsCache.Convert(newItems.IndexOf);
|
|
list.RemoveAll(IndexNotFound);
|
|
dataSource = newItems;
|
|
if (KeepSelection)
|
|
{
|
|
SilentSelect(list);
|
|
}
|
|
SelectedItemsCache = SelectedItems;
|
|
UpdateView();
|
|
DataSource.OnChange += UpdateItems;
|
|
}
|
|
|
|
protected virtual float CalculateBottomFillerSize()
|
|
{
|
|
if (bottomHiddenItems == 0)
|
|
{
|
|
return 0f;
|
|
}
|
|
return Mathf.Max(0f, (float)bottomHiddenItems * GetItemSize() - LayoutBridge.GetSpacing());
|
|
}
|
|
|
|
protected virtual float CalculateTopFillerSize()
|
|
{
|
|
if (topHiddenItems == 0)
|
|
{
|
|
return 0f;
|
|
}
|
|
return Mathf.Max(0f, (float)topHiddenItems * GetItemSize() - LayoutBridge.GetSpacing());
|
|
}
|
|
|
|
public override bool IsValid(int index)
|
|
{
|
|
return index >= 0 && index < DataSource.Count;
|
|
}
|
|
|
|
protected override void Coloring(ListViewItem component)
|
|
{
|
|
if (!(component == null))
|
|
{
|
|
if (base.SelectedIndicies.Contains(component.Index))
|
|
{
|
|
SelectColoring(component);
|
|
}
|
|
else
|
|
{
|
|
DefaultColoring(component);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override void HighlightColoring(ListViewItem component)
|
|
{
|
|
if (!IsSelected(component.Index))
|
|
{
|
|
HighlightColoring(component as TComponent);
|
|
}
|
|
}
|
|
|
|
protected virtual void HighlightColoring(TComponent component)
|
|
{
|
|
component.Background.color = HighlightedBackgroundColor;
|
|
}
|
|
|
|
protected virtual void SelectColoring(ListViewItem component)
|
|
{
|
|
if (!(component == null))
|
|
{
|
|
SelectColoring(component as TComponent);
|
|
}
|
|
}
|
|
|
|
protected virtual void SelectColoring(TComponent component)
|
|
{
|
|
component.Background.color = SelectedBackgroundColor;
|
|
}
|
|
|
|
protected virtual void DefaultColoring(ListViewItem component)
|
|
{
|
|
if (!(component == null))
|
|
{
|
|
DefaultColoring(component as TComponent);
|
|
}
|
|
}
|
|
|
|
protected virtual void DefaultColoring(TComponent component)
|
|
{
|
|
component.Background.color = DefaultBackgroundColor;
|
|
}
|
|
|
|
private void UpdateColors()
|
|
{
|
|
components.ForEach(delegate(TComponent x)
|
|
{
|
|
Coloring(x);
|
|
});
|
|
}
|
|
|
|
protected override void OnDestroy()
|
|
{
|
|
layout = null;
|
|
LayoutBridge = null;
|
|
OnSelect.RemoveListener(OnSelectCallback);
|
|
OnDeselect.RemoveListener(OnDeselectCallback);
|
|
ScrollRect = null;
|
|
RemoveCallbacks();
|
|
base.OnDestroy();
|
|
}
|
|
|
|
public override void ForEachComponent(Action<ListViewItem> func)
|
|
{
|
|
base.ForEachComponent(func);
|
|
func(DefaultItem);
|
|
((IEnumerable<TComponent>)componentsCache).Select((Func<TComponent, ListViewItem>)((TComponent x) => x)).ForEach(func);
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (needResize)
|
|
{
|
|
Resize();
|
|
}
|
|
if (IsEndScrolling())
|
|
{
|
|
EndScrolling();
|
|
}
|
|
}
|
|
|
|
public virtual void OnEnable()
|
|
{
|
|
StartCoroutine(ForceRebuild());
|
|
}
|
|
|
|
public IEnumerator ForceRebuild()
|
|
{
|
|
yield return null;
|
|
ForEachComponent(MarkLayoutForRebuild);
|
|
}
|
|
|
|
public void MarkLayoutForRebuild(ListViewItem item)
|
|
{
|
|
LayoutRebuilder.MarkLayoutForRebuild(item.transform as RectTransform);
|
|
}
|
|
|
|
private void StartScrolling()
|
|
{
|
|
lastScrollingTime = Time.time;
|
|
if (!scrolling)
|
|
{
|
|
scrolling = true;
|
|
OnStartScrolling.Invoke();
|
|
}
|
|
}
|
|
|
|
private bool IsEndScrolling()
|
|
{
|
|
if (!scrolling)
|
|
{
|
|
return false;
|
|
}
|
|
return lastScrollingTime + EndScrollDelay <= Time.time;
|
|
}
|
|
|
|
private void EndScrolling()
|
|
{
|
|
scrolling = false;
|
|
OnEndScrolling.Invoke();
|
|
}
|
|
|
|
public void SetNeedResize()
|
|
{
|
|
if (CanOptimize())
|
|
{
|
|
needResize = true;
|
|
}
|
|
}
|
|
}
|
|
}
|