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

378 lines
9.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 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);
}
}