#if UNITY_2019_4_OR_NEWER using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; using UnityEditor.UIElements; using UnityEngine.UIElements; namespace YooAsset.Editor { /// /// Unity2022版本以上推荐官方类:MultiColumnListView组件 /// public class TableViewer : VisualElement { public new class UxmlFactory : UxmlFactory { } private readonly Toolbar _toolbar; private readonly ListView _listView; private readonly List _columns = new List(10); private List _itemsSource; private List _sortingDatas; // 排序相关 private string _sortingHeader; private bool _descendingSort = true; /// /// 数据源 /// public List itemsSource { get { return _itemsSource; } set { if (CheckItemsSource(value)) { _itemsSource = value; _sortingDatas = value; } } } /// /// 选中的数据列表 /// public List selectedItems { get { #if UNITY_2020_3_OR_NEWER return _listView.selectedItems.Cast().ToList(); #else List result = new List(); result.Add(_listView.selectedItem as ITableData); return result; #endif } } /// /// 单元视图交互事件 /// public Action ClickTableDataEvent; /// /// 单元视图交互事件 /// public Action ClickTableHeadEvent; /// /// 单元视图变化事件 /// public Action SelectionChangedEvent; public TableViewer() { this.style.flexShrink = 1f; this.style.flexGrow = 1f; // 定义标题栏 _toolbar = new Toolbar(); // 定义列表视图 _listView = new ListView(); _listView.style.flexShrink = 1f; _listView.style.flexGrow = 1f; _listView.makeItem = MakeListViewElement; _listView.bindItem = BindListViewElement; _listView.selectionType = SelectionType.Multiple; _listView.RegisterCallback(OnClickListItem); #if UNITY_2022_3_OR_NEWER _listView.selectionChanged += OnSelectionChanged; #elif UNITY_2020_1_OR_NEWER _listView.onSelectionChange += OnSelectionChanged; #else _listView.onSelectionChanged += OnSelectionChanged; #endif this.Add(_toolbar); this.Add(_listView); } /// /// 获取标题UI元素 /// public VisualElement GetHeaderElement(string elementName) { return _toolbar.Q(elementName); } /// /// 添加单元列 /// public void AddColumn(TableColumn column) { var toolbarBtn = new ToolbarButton(); toolbarBtn.userData = column; toolbarBtn.name = column.ElementName; toolbarBtn.text = column.HeaderTitle; toolbarBtn.style.flexGrow = 0; toolbarBtn.style.width = column.ColumnStyle.Width; toolbarBtn.style.minWidth = column.ColumnStyle.Width; toolbarBtn.style.maxWidth = column.ColumnStyle.Width; toolbarBtn.clickable.clickedWithEventInfo += OnClickTableHead; SetCellElementStyle(toolbarBtn); _toolbar.Add(toolbarBtn); _columns.Add(column); // 可伸缩控制柄 if (column.ColumnStyle.Stretchable) { int handleWidth = 3; int minWidth = (int)column.ColumnStyle.MinWidth.value; int maxWidth = (int)column.ColumnStyle.MaxWidth.value; var resizeHandle = new ResizeHandle(handleWidth, toolbarBtn, minWidth, maxWidth); resizeHandle.ResizeChanged += (float value) => { float width = Mathf.Clamp(value, column.ColumnStyle.MinWidth.value, column.ColumnStyle.MaxWidth.value); column.ColumnStyle.Width = width; foreach (var element in column.CellElements) { element.style.width = width; element.style.minWidth = width; element.style.maxWidth = width; } }; _toolbar.Add(resizeHandle); } // 计算索引值 column.ColumnIndex = _columns.Count - 1; if (column.ColumnStyle.Sortable == false) toolbarBtn.SetEnabled(false); } /// /// 添加单元列集合 /// public void AddColumns(IList columns) { foreach (var column in columns) { AddColumn(column); } } /// /// 重建表格视图 /// public void RebuildView() { if (_itemsSource == null) return; var itemsSource = _sortingDatas.Where(row => row.Visible); _listView.Clear(); _listView.ClearSelection(); _listView.itemsSource = itemsSource.ToList(); _listView.Rebuild(); // 刷新标题栏 RefreshToobar(); } private void RefreshToobar() { // 设置为原始标题 foreach (var column in _columns) { var toobarButton = _toolbar.Q(column.ElementName); toobarButton.text = column.HeaderTitle; } // 设置元素数量 foreach (var column in _columns) { if (column.ColumnStyle.Counter) { var toobarButton = GetHeaderElement(column.ElementName) as ToolbarButton; toobarButton.text = $"{toobarButton.text} ({itemsSource.Count()})"; } } // 设置展示单位 foreach (var column in _columns) { if (string.IsNullOrEmpty(column.ColumnStyle.Units) == false) { var toobarButton = GetHeaderElement(column.ElementName) as ToolbarButton; toobarButton.text = $"{toobarButton.text} ({column.ColumnStyle.Units})"; } } // 设置升降符号 if (string.IsNullOrEmpty(_sortingHeader) == false) { var _toobarButton = _toolbar.Q(_sortingHeader); if (_descendingSort) _toobarButton.text = $"{_toobarButton.text} ↓"; else _toobarButton.text = $"{_toobarButton.text} ↑"; } } /// /// 清空所有数据 /// public void ClearAll(bool clearColumns, bool clearSource) { if (clearColumns) { _columns.Clear(); _toolbar.Clear(); } if (clearSource) { if (_itemsSource != null) _itemsSource.Clear(); if (_sortingDatas != null) _sortingDatas.Clear(); _listView.Clear(); _listView.ClearSelection(); } } private void OnClickListItem(PointerDownEvent evt) { var selectData = _listView.selectedItem as ITableData; if (selectData == null) return; ClickTableDataEvent?.Invoke(evt, selectData); } private void OnClickTableHead(EventBase eventBase) { if (_itemsSource == null) return; ToolbarButton toolbarBtn = eventBase.target as ToolbarButton; var clickedColumn = toolbarBtn.userData as TableColumn; if (clickedColumn == null) return; ClickTableHeadEvent?.Invoke(clickedColumn); if (clickedColumn.ColumnStyle.Sortable == false) return; if (_sortingHeader != clickedColumn.ElementName) { _sortingHeader = clickedColumn.ElementName; _descendingSort = false; } else { _descendingSort = !_descendingSort; } // 升降排序 if (_descendingSort) _sortingDatas = _itemsSource.OrderByDescending(tableData => tableData.Cells[clickedColumn.ColumnIndex]).ToList(); else _sortingDatas = _itemsSource.OrderBy(tableData => tableData.Cells[clickedColumn.ColumnIndex]).ToList(); // 刷新数据表 RebuildView(); } private void OnSelectionChanged(IEnumerable items) { foreach (var item in items) { var tableData = item as ITableData; SelectionChangedEvent?.Invoke(tableData); break; } } private bool CheckItemsSource(List itemsSource) { if (itemsSource == null) return false; if (itemsSource.Count > 0) { int cellCount = itemsSource[0].Cells.Count; for (int i = 0; i < itemsSource.Count; i++) { var tableData = itemsSource[i]; if (tableData == null) { Debug.LogWarning($"Items source has null instance !"); return false; } if (tableData.Cells == null || tableData.Cells.Count == 0) { Debug.LogWarning($"Items source data has empty cells !"); return false; } if (tableData.Cells.Count != cellCount) { Debug.LogWarning($"Items source data has inconsisten cells count ! Item index {i}"); return false; } } } return true; } private VisualElement MakeListViewElement() { VisualElement listViewElement = new VisualElement(); listViewElement.style.flexDirection = FlexDirection.Row; foreach (var column in _columns) { var cellElement = column.MakeCell.Invoke(); cellElement.name = column.ElementName; cellElement.style.flexGrow = 0f; cellElement.style.width = column.ColumnStyle.Width; cellElement.style.minWidth = column.ColumnStyle.Width; cellElement.style.maxWidth = column.ColumnStyle.Width; SetCellElementStyle(cellElement); listViewElement.Add(cellElement); column.CellElements.Add(cellElement); } return listViewElement; } private void BindListViewElement(VisualElement listViewElement, int index) { var sourceDatas = _listView.itemsSource as List; var tableData = sourceDatas[index]; foreach (var colum in _columns) { var cellElement = listViewElement.Q(colum.ElementName); var tableCell = tableData.Cells[colum.ColumnIndex]; colum.BindCell.Invoke(cellElement, tableData, tableCell); } } private void SetCellElementStyle(VisualElement element) { StyleLength defaultStyle = new StyleLength(1f); element.style.paddingTop = defaultStyle; element.style.paddingBottom = defaultStyle; element.style.marginTop = defaultStyle; element.style.marginBottom = defaultStyle; element.style.paddingLeft = 1; element.style.paddingRight = 1; element.style.marginLeft = 0; element.style.marginRight = 0; } } } #endif