using System; using System.Collections.Generic; using FairyGUI; using UnityEngine; namespace NBF { public class ListSelector { private GList _list; private readonly List _ignores = new List(); // private readonly List _items = new List(); 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 } }