202 lines
5.5 KiB
C#
202 lines
5.5 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using FairyGUI;
|
||
using UnityEngine;
|
||
|
||
namespace NBF
|
||
{
|
||
public class ListSelector
|
||
{
|
||
private GList _list;
|
||
private readonly List<Type> _ignores = new List<Type>();
|
||
// private readonly List<GObject> _items = new List<GObject>();
|
||
|
||
private float itemWidth = 200f;
|
||
private float itemHeight = 180f;
|
||
|
||
public object SelectedItem => _list.selectedIndex > 0 ? _list.GetChildAt(_list.selectedIndex) : null;
|
||
|
||
public ListSelector(GList list, params Type[] ignores)
|
||
{
|
||
_list = list;
|
||
if (ignores != null && ignores.Length > 0)
|
||
{
|
||
_ignores.AddRange(ignores);
|
||
}
|
||
}
|
||
|
||
#region 数据刷新
|
||
|
||
public void Refresh()
|
||
{
|
||
var children = _list.GetChildren();
|
||
foreach (var item in children)
|
||
{
|
||
if (_ignores.Contains(item.GetType())) continue;
|
||
itemWidth = item.width;
|
||
itemHeight = item.height;
|
||
break;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 操作
|
||
|
||
public void Up()
|
||
{
|
||
Move(Vector2.up);
|
||
}
|
||
|
||
public void Down()
|
||
{
|
||
Move(Vector2.down);
|
||
}
|
||
|
||
public void Right()
|
||
{
|
||
Move(Vector2.right);
|
||
}
|
||
|
||
public void Left()
|
||
{
|
||
Move(Vector2.left);
|
||
}
|
||
|
||
public void Move(Vector2 direction)
|
||
{
|
||
if (_list.selectedIndex == -1)
|
||
{
|
||
// 首次选择第一个可选中项
|
||
SelectFirstSelectable();
|
||
return;
|
||
}
|
||
|
||
var currentPos = GetItemPosition(_list.selectedIndex);
|
||
var nearestIndex = FindNearestSelectableItem(currentPos, direction);
|
||
|
||
// 如果是左右移动且未找到目标,则尝试寻找前一个或后一个可选项
|
||
if (nearestIndex == -1 && (direction == Vector2.left || direction == Vector2.right))
|
||
{
|
||
if (direction == Vector2.left)
|
||
{
|
||
// 寻找前一个可选项
|
||
nearestIndex = FindPreviousSelectableItem(_list.selectedIndex);
|
||
}
|
||
else if (direction == Vector2.right)
|
||
{
|
||
// 寻找后一个可选项
|
||
nearestIndex = FindNextSelectableItem(_list.selectedIndex);
|
||
}
|
||
}
|
||
|
||
if (nearestIndex != -1)
|
||
{
|
||
SetSelection(nearestIndex);
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 内部方法
|
||
|
||
private Vector2 GetItemPosition(int index)
|
||
{
|
||
var item = _list.GetChildAt(index);
|
||
return item.position;
|
||
}
|
||
|
||
private int FindNearestSelectableItem(Vector2 fromPos, Vector2 direction)
|
||
{
|
||
var bestIndex = -1;
|
||
var bestDistance = float.MaxValue;
|
||
|
||
for (var i = 0; i < _list.numItems; i++)
|
||
{
|
||
if (!IsSelectableItem(i)) continue;
|
||
|
||
var targetPos = GetItemPosition(i);
|
||
var diff = targetPos - fromPos;
|
||
|
||
// 检查方向匹配度
|
||
if (IsDirectionMatch(direction, diff))
|
||
{
|
||
var distance = Vector2.Distance(fromPos, targetPos);
|
||
if (distance < bestDistance && distance > 0.1f)
|
||
{
|
||
bestDistance = distance;
|
||
bestIndex = i;
|
||
}
|
||
}
|
||
}
|
||
|
||
return bestIndex;
|
||
}
|
||
|
||
private int FindPreviousSelectableItem(int currentIndex)
|
||
{
|
||
for (int i = currentIndex - 1; i >= 0; i--)
|
||
{
|
||
if (IsSelectableItem(i))
|
||
return i;
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
private int FindNextSelectableItem(int currentIndex)
|
||
{
|
||
for (int i = currentIndex + 1; i < _list.numItems; i++)
|
||
{
|
||
if (IsSelectableItem(i))
|
||
return i;
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
private bool IsDirectionMatch(Vector2 direction, Vector2 diff)
|
||
{
|
||
if (direction == Vector2.up)
|
||
return diff.y < 0 && Mathf.Abs(diff.x) < itemWidth; // 修正:向上应该是Y值更小
|
||
if (direction == Vector2.down)
|
||
return diff.y > 0 && Mathf.Abs(diff.x) < itemWidth; // 修正:向下应该是Y值更大
|
||
if (direction == Vector2.left)
|
||
return diff.x < 0 && Mathf.Abs(diff.y) < itemHeight;
|
||
if (direction == Vector2.right)
|
||
return diff.x > 0 && Mathf.Abs(diff.y) < itemHeight;
|
||
return false;
|
||
}
|
||
|
||
private bool IsSelectableItem(int index)
|
||
{
|
||
var item = _list.GetChildAt(index);
|
||
var ret = !_ignores.Contains(item.GetType());
|
||
if (item.GetType() == typeof(ListTitleItem))
|
||
{
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
private void SelectFirstSelectable()
|
||
{
|
||
for (var i = 0; i < _list.numItems; i++)
|
||
{
|
||
if (IsSelectableItem(i))
|
||
{
|
||
SetSelection(i);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
private void SetSelection(int index)
|
||
{
|
||
_list.selectedIndex = index;
|
||
_list.ScrollToView(index, true);
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
} |