DCS/ruiyiweiUX/Assets/Scripts/UI/ScrollableListView.cs

378 lines
9.5 KiB
C#
Raw Normal View History

2026-06-09 13:59:11 +08:00
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 通用滑动列表组件
/// 支持动态添加、删除和更新列表项,带有滚动功能
/// </summary>
public class ScrollableListView : MonoBehaviour
{
[Header("滚动设置")]
public ScrollRect ScrollRect; // 滚动组件
public RectTransform Content; // 内容容器
public GameObject ItemPrefab; // 列表项预制件
[Header("布局设置")]
public float ItemHeight = 80f; // 列表项高度
public float ItemSpacing = 5f; // 列表项间距
public bool AutoResize = true; // 自动调整内容大小
[Header("样式设置")]
public Color AlternateRowColor = new Color(0.9f, 0.9f, 0.9f, 0.3f); // 交替行颜色
public bool UseAlternateRowColors = true; // 是否使用交替行颜色
private List<ScrollableListItem> _items = new List<ScrollableListItem>();
private VerticalLayoutGroup _layoutGroup;
void Awake()
{
InitializeComponents();
}
private void InitializeComponents()
{
// 如果没有设置ScrollRect尝试获取
if (ScrollRect == null)
{
ScrollRect = GetComponent<ScrollRect>();
}
// 如果没有设置Content尝试从ScrollRect获取
if (Content == null && ScrollRect != null)
{
Content = ScrollRect.content;
}
// 确保Content有VerticalLayoutGroup
if (Content != null)
{
_layoutGroup = Content.GetComponent<VerticalLayoutGroup>();
if (_layoutGroup == null)
{
_layoutGroup = Content.gameObject.AddComponent<VerticalLayoutGroup>();
}
// 配置VerticalLayoutGroup
_layoutGroup.childControlHeight = false;
_layoutGroup.childControlWidth = true;
_layoutGroup.childForceExpandHeight = false;
_layoutGroup.childForceExpandWidth = false;
_layoutGroup.spacing = ItemSpacing;
_layoutGroup.padding = new RectOffset(5, 5, 5, 5);
}
// 确保ItemPrefab不活跃
if (ItemPrefab != null)
{
ItemPrefab.SetActive(false);
}
}
/// <summary>
/// 添加列表项
/// </summary>
public ScrollableListItem AddItem(object data = null)
{
if (ItemPrefab == null || Content == null)
{
Debug.LogError("ItemPrefab or Content is null!");
return null;
}
// 创建新项
GameObject itemGO = Instantiate(ItemPrefab, Content);
itemGO.SetActive(true);
// 设置高度
RectTransform itemRect = itemGO.GetComponent<RectTransform>();
if (itemRect != null)
{
itemRect.sizeDelta = new Vector2(itemRect.sizeDelta.x, ItemHeight);
}
// 获取或添加ScrollableListItem组件
ScrollableListItem item = itemGO.GetComponent<ScrollableListItem>();
if (item == null)
{
item = itemGO.AddComponent<ScrollableListItem>();
}
// 设置数据和索引
item.Initialize(data, _items.Count, this);
_items.Add(item);
// 设置交替行颜色
if (UseAlternateRowColors && _items.Count % 2 == 0)
{
var bgImage = itemGO.GetComponent<Image>();
if (bgImage == null)
{
bgImage = itemGO.AddComponent<Image>();
}
bgImage.color = AlternateRowColor;
}
// 更新内容大小
if (AutoResize)
{
UpdateContentSize();
}
return item;
}
/// <summary>
/// 删除指定列表项
/// </summary>
public void RemoveItem(ScrollableListItem item)
{
if (_items.Remove(item))
{
if (item.gameObject != null)
{
Destroy(item.gameObject);
}
// 更新剩余项的索引
UpdateItemIndices();
if (AutoResize)
{
UpdateContentSize();
}
}
}
/// <summary>
/// 删除指定索引的列表项
/// </summary>
public void RemoveItemAt(int index)
{
if (index >= 0 && index < _items.Count)
{
RemoveItem(_items[index]);
}
}
/// <summary>
/// 清空所有列表项
/// </summary>
public void ClearItems()
{
foreach (var item in _items)
{
if (item != null && item.gameObject != null)
{
Destroy(item.gameObject);
}
}
_items.Clear();
if (AutoResize)
{
UpdateContentSize();
}
}
/// <summary>
/// 获取列表项数量
/// </summary>
public int GetItemCount()
{
return _items.Count;
}
/// <summary>
/// 获取指定索引的列表项
/// </summary>
public ScrollableListItem GetItem(int index)
{
if (index >= 0 && index < _items.Count)
{
return _items[index];
}
return null;
}
/// <summary>
/// 获取所有列表项
/// </summary>
public List<ScrollableListItem> GetAllItems()
{
return new List<ScrollableListItem>(_items);
}
/// <summary>
/// 滚动到指定列表项
/// </summary>
public void ScrollToItem(ScrollableListItem item)
{
if (ScrollRect == null || Content == null || item == null) return;
int index = _items.IndexOf(item);
if (index >= 0)
{
ScrollToIndex(index);
}
}
/// <summary>
/// 滚动到指定索引
/// </summary>
public void ScrollToIndex(int index)
{
if (ScrollRect == null || Content == null || index < 0 || index >= _items.Count) return;
float itemY = index * (ItemHeight + ItemSpacing);
float contentHeight = Content.rect.height;
float viewportHeight = ScrollRect.viewport.rect.height;
if (contentHeight > viewportHeight)
{
float normalizedPosition = 1f - (itemY / (contentHeight - viewportHeight));
normalizedPosition = Mathf.Clamp01(normalizedPosition);
ScrollRect.verticalNormalizedPosition = normalizedPosition;
}
}
/// <summary>
/// 滚动到顶部
/// </summary>
public void ScrollToTop()
{
if (ScrollRect != null)
{
ScrollRect.verticalNormalizedPosition = 1f;
}
}
/// <summary>
/// 滚动到底部
/// </summary>
public void ScrollToBottom()
{
if (ScrollRect != null)
{
ScrollRect.verticalNormalizedPosition = 0f;
}
}
/// <summary>
/// 更新内容大小
/// </summary>
private void UpdateContentSize()
{
if (Content == null) return;
float totalHeight = _items.Count * ItemHeight + (_items.Count - 1) * ItemSpacing + _layoutGroup.padding.top + _layoutGroup.padding.bottom;
Content.sizeDelta = new Vector2(Content.sizeDelta.x, totalHeight);
}
/// <summary>
/// 更新所有项的索引
/// </summary>
private void UpdateItemIndices()
{
for (int i = 0; i < _items.Count; i++)
{
if (_items[i] != null)
{
_items[i].SetIndex(i);
}
}
}
/// <summary>
/// 刷新列表显示
/// </summary>
public void RefreshList()
{
// 移除已被销毁的项
_items.RemoveAll(item => item == null || item.gameObject == null);
// 更新索引
UpdateItemIndices();
// 更新内容大小
if (AutoResize)
{
UpdateContentSize();
}
}
}
/// <summary>
/// 滚动列表项基类
/// </summary>
public class ScrollableListItem : MonoBehaviour
{
public object Data { get; private set; }
public int Index { get; private set; }
public ScrollableListView ListView { get; private set; }
public event Action<ScrollableListItem> OnItemClicked;
public event Action<ScrollableListItem> OnItemSelected;
private Button _button;
private Toggle _toggle;
void Awake()
{
// 获取按钮组件
_button = GetComponent<Button>();
if (_button != null)
{
_button.onClick.AddListener(OnButtonClicked);
}
// 获取Toggle组件
_toggle = GetComponent<Toggle>();
if (_toggle != null)
{
_toggle.onValueChanged.AddListener(OnToggleChanged);
}
}
public void Initialize(object data, int index, ScrollableListView listView)
{
Data = data;
Index = index;
ListView = listView;
// 子类可以重写此方法来更新UI
UpdateUI();
}
public void SetIndex(int index)
{
Index = index;
}
protected virtual void UpdateUI()
{
// 子类重写此方法来更新UI显示
}
private void OnButtonClicked()
{
OnItemClicked?.Invoke(this);
}
private void OnToggleChanged(bool isOn)
{
if (isOn)
{
OnItemSelected?.Invoke(this);
}
}
/// <summary>
/// 删除此项
/// </summary>
public void RemoveFromList()
{
ListView?.RemoveItem(this);
}
}