天津23维预案
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

316 lines
8.5 KiB

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using System;
using System.Linq;
namespace UIWidgets {
/// <summary>
/// Tile view.
/// </summary>
public class TileView<TComponent,TItem> : ListViewCustom<TComponent,TItem> where TComponent : ListViewItem {
int itemsPerRow;
int itemsPerColumn;
/// <summary>
/// Determines whether this instance can optimize.
/// </summary>
/// <returns><c>true</c> if this instance can optimize; otherwise, <c>false</c>.</returns>
protected override bool CanOptimize()
{
var scrollRectSpecified = scrollRect!=null;
var containerSpecified = Container!=null;
var currentLayout = containerSpecified ? ((layout!=null) ? layout : Container.GetComponent<LayoutGroup>()) : null;
var validLayout = currentLayout is EasyLayout.EasyLayout;
return scrollRectSpecified && validLayout;
}
/// <summary>
/// Scrolls to item with specifid index.
/// </summary>
/// <param name="index">Index.</param>
public override void ScrollTo(int index)
{
if (!CanOptimize())
{
return ;
}
var first_visible = GetFirstVisibleIndex(true);
var last_visible = GetLastVisibleIndex(true);
var block_index = Mathf.FloorToInt((float)index / (float)ItemsPerBlock());
if (first_visible > block_index)
{
SetScrollValue(GetItemPosition(index));
}
else if (last_visible < block_index)
{
SetScrollValue(GetItemPositionBottom(index));
}
}
/// <summary>
/// Gets the item position.
/// </summary>
/// <returns>The item position.</returns>
/// <param name="index">Index.</param>
public override float GetItemPosition(int index)
{
var block_index = Mathf.FloorToInt((float)index / (float)ItemsPerBlock());
return block_index * GetItemSize() - GetItemSpacing();
}
/// <summary>
/// Calculates the max count of visible items.
/// </summary>
protected override void CalculateMaxVisibleItems()
{
var spacing = LayoutBridge.GetSpacing();
if (IsHorizontal())
{
var height = scrollHeight + spacing - LayoutBridge.GetFullMargin();
itemsPerRow = Mathf.CeilToInt(scrollWidth / itemWidth) + 1;
itemsPerRow = Mathf.Max(2, itemsPerRow);
itemsPerColumn = Mathf.FloorToInt(height / (itemHeight + spacing));
itemsPerColumn = Mathf.Max(1, itemsPerColumn);
}
else
{
var width = scrollWidth + spacing - LayoutBridge.GetFullMargin();
itemsPerRow = Mathf.FloorToInt(width / (itemWidth + spacing));
itemsPerRow = Mathf.Max(1, itemsPerRow);
itemsPerColumn = Mathf.CeilToInt(scrollHeight / itemHeight) + 1;
itemsPerColumn = Mathf.Max(2, itemsPerColumn);
}
maxVisibleItems = itemsPerRow * itemsPerColumn;
}
/// <summary>
/// Gets the index of first visible item.
/// </summary>
/// <returns>The first visible index.</returns>
/// <param name="strict">If set to <c>true</c> strict.</param>
protected override int GetFirstVisibleIndex(bool strict=false)
{
return Mathf.Max(0, base.GetFirstVisibleIndex(strict) * ItemsPerBlock());
}
/// <summary>
/// Gets the index of last visible item.
/// </summary>
/// <returns>The last visible index.</returns>
/// <param name="strict">If set to <c>true</c> strict.</param>
protected override int GetLastVisibleIndex(bool strict=false)
{
return (base.GetLastVisibleIndex(strict) + 1) * ItemsPerBlock() - 1;
}
/// <summary>
/// Scrolls the update.
/// </summary>
protected override void ScrollUpdate()
{
var oldTopHiddenItems = topHiddenItems;
topHiddenItems = GetFirstVisibleIndex();
if (topHiddenItems > (DataSource.Count - 1))
{
topHiddenItems = Mathf.Max(0, DataSource.Count - 2);
}
if (oldTopHiddenItems==topHiddenItems)
{
return ;
}
if ((CanOptimize()) && (DataSource.Count > 0))
{
visibleItems = (maxVisibleItems < DataSource.Count) ? maxVisibleItems : DataSource.Count;
}
else
{
visibleItems = DataSource.Count;
}
if ((topHiddenItems + visibleItems) > DataSource.Count)
{
visibleItems = DataSource.Count - topHiddenItems;
if (visibleItems < ItemsPerBlock())
{
visibleItems = Mathf.Min(DataSource.Count, visibleItems + ItemsPerBlock());
topHiddenItems = DataSource.Count - visibleItems;
}
}
RemoveCallbacks();
UpdateComponentsCount();
bottomHiddenItems = Mathf.Max(0, DataSource.Count - visibleItems - topHiddenItems);
var new_visible_range = Enumerable.Range(topHiddenItems, visibleItems).ToList();
var current_visible_range = components.Convert<TComponent,int>(GetComponentIndex);
var new_indicies_to_change = new_visible_range.Except(current_visible_range).ToList();
var components_to_change = new Stack<TComponent>(components.Where(x => !new_visible_range.Contains(x.Index)));
new_indicies_to_change.ForEach(index => {
var component = components_to_change.Pop();
component.Index = index;
SetData(component, DataSource[index]);
Coloring(component as ListViewItem);
});
components.Sort(ComponentsComparer);
components.ForEach(SetComponentAsLastSibling);
AddCallbacks();
if (LayoutBridge!=null)
{
LayoutBridge.SetFiller(CalculateTopFillerSize(), CalculateBottomFillerSize());
LayoutBridge.UpdateLayout();
}
}
/// <summary>
/// Raises the item move event.
/// </summary>
/// <param name="eventData">Event data.</param>
/// <param name="item">Item.</param>
protected override void OnItemMove(AxisEventData eventData, ListViewItem item)
{
var block = item.Index % ItemsPerBlock();
switch (eventData.moveDir)
{
case MoveDirection.Left:
if (block > 0)
{
SelectComponentByIndex(item.Index - 1);
}
break;
case MoveDirection.Right:
if (block < (ItemsPerBlock() - 1))
{
SelectComponentByIndex(item.Index + 1);
}
break;
case MoveDirection.Up:
var index_up = item.Index - ItemsPerBlock();
if (IsValid(index_up))
{
SelectComponentByIndex(index_up);
}
break;
case MoveDirection.Down:
var index_down = item.Index + ItemsPerBlock();
if (IsValid(index_down))
{
SelectComponentByIndex(index_down);
}
break;
}
}
/// <summary>
/// Gets the index of the nearest item.
/// </summary>
/// <returns>The nearest item index.</returns>
/// <param name="point">Point.</param>
public override int GetNearestIndex(Vector2 point)
{
if (IsSortEnabled())
{
return -1;
}
// block index
var pos_block = IsHorizontal() ? point.x : -point.y;
var block = Mathf.RoundToInt(pos_block / GetItemSize());
// item index in block
var pos_elem = IsHorizontal() ? -point.y : point.x;
var size = (IsHorizontal()) ? itemHeight + LayoutBridge.GetSpacing() : itemWidth + LayoutBridge.GetSpacing();
var k = Mathf.FloorToInt(pos_elem / size);
return block * GetItemsPerBlock() + k;
}
/// <summary>
/// Count of items the per block.
/// </summary>
/// <returns>The per block.</returns>
int ItemsPerBlock()
{
return IsHorizontal() ? itemsPerColumn : itemsPerRow;
}
/// <summary>
/// Gets the blocks count.
/// </summary>
/// <returns>The blocks count.</returns>
/// <param name="items">Items.</param>
int GetBlocksCount(int items)
{
return Mathf.CeilToInt((float)items / (float)ItemsPerBlock());
}
/// <summary>
/// Calculates the size of the bottom filler.
/// </summary>
/// <returns>The bottom filler size.</returns>
protected override float CalculateBottomFillerSize()
{
var blocks = GetBlocksCount(bottomHiddenItems);
if (blocks==0)
{
return 0f;
}
return Mathf.Max(0, blocks * GetItemSize() - LayoutBridge.GetSpacing());
}
/// <summary>
/// Calculates the size of the top filler.
/// </summary>
/// <returns>The top filler size.</returns>
protected override float CalculateTopFillerSize()
{
var blocks = GetBlocksCount(topHiddenItems);
if (blocks==0)
{
return 0f;
}
return Mathf.Max(0, GetBlocksCount(topHiddenItems) * GetItemSize() - LayoutBridge.GetSpacing());
}
#region ListViewPaginator support
/// <summary>
/// Gets the items per block count.
/// </summary>
/// <returns>The items per block.</returns>
public override int GetItemsPerBlock()
{
return ItemsPerBlock();
}
/// <summary>
/// Gets the index of the nearest item.
/// </summary>
/// <returns>The nearest item index.</returns>
public override int GetNearestItemIndex()
{
return base.GetNearestItemIndex() * ItemsPerBlock();
}
#endregion
}
}