Files
Fishing2/Assets/Scripts/UI/Common/List/ListSelector.cs
2025-10-31 09:48:12 +08:00

202 lines
5.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}
}