diff --git a/Assets/YooAsset/Editor/UIElements/TableView.meta b/Assets/YooAsset/Editor/UIElements/TableView.meta
new file mode 100644
index 00000000..d28ac593
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e5f8691a7e0c67d4ab790b703925cd75
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/ColumnStyle.cs b/Assets/YooAsset/Editor/UIElements/TableView/ColumnStyle.cs
new file mode 100644
index 00000000..e2ed4281
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/ColumnStyle.cs
@@ -0,0 +1,45 @@
+#if UNITY_2019_4_OR_NEWER
+using System;
+using UnityEditor;
+using UnityEngine;
+using UnityEditor.UIElements;
+using UnityEngine.UIElements;
+
+namespace YooAsset.Editor
+{
+ public class ColumnStyle
+ {
+ public const float MaxValue = 8388608f;
+
+ ///
+ /// 单元列宽度
+ ///
+ public Length Width = 100f;
+
+ ///
+ /// 单元列最小宽度
+ ///
+ public Length MinWidth = 30f;
+
+ ///
+ /// 单元列最大宽度
+ ///
+ public Length MaxWidth = MaxValue;
+
+ ///
+ /// 可伸缩
+ ///
+ public bool Stretchable = false;
+
+ ///
+ /// 可搜索
+ ///
+ public bool Searchable = false;
+
+ ///
+ /// 可排序
+ ///
+ public bool Sortable = false;
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/ColumnStyle.cs.meta b/Assets/YooAsset/Editor/UIElements/TableView/ColumnStyle.cs.meta
new file mode 100644
index 00000000..c9b12a2f
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/ColumnStyle.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6a74bbcb5d814f94fb54042ec3b6d94c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells.meta b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells.meta
new file mode 100644
index 00000000..22a17172
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8b25809b75e1e7141aff3c2011845aab
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/AssetPathCell.cs b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/AssetPathCell.cs
new file mode 100644
index 00000000..68d929be
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/AssetPathCell.cs
@@ -0,0 +1,12 @@
+#if UNITY_2019_4_OR_NEWER
+
+namespace YooAsset.Editor
+{
+ public class AssetPathCell : StringValueCell
+ {
+ public AssetPathCell(string headerTitle) : base(headerTitle)
+ {
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/AssetPathCell.cs.meta b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/AssetPathCell.cs.meta
new file mode 100644
index 00000000..380a8178
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/AssetPathCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ed1c077653e577846ba29aadb91f13ec
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/ButtonCell.cs b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/ButtonCell.cs
new file mode 100644
index 00000000..79016ac2
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/ButtonCell.cs
@@ -0,0 +1,20 @@
+#if UNITY_2019_4_OR_NEWER
+using System;
+
+namespace YooAsset.Editor
+{
+ public class ButtonCell : ITableCell, IComparable
+ {
+ public object CellValue { set; get; }
+
+ public object GetDisplayObject()
+ {
+ return string.Empty;
+ }
+ public int CompareTo(object other)
+ {
+ return 1;
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/ButtonCell.cs.meta b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/ButtonCell.cs.meta
new file mode 100644
index 00000000..6282cb87
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/ButtonCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: fe6c2551d70d6934da0b6afce3f1062c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/IntegerValueCell.cs b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/IntegerValueCell.cs
new file mode 100644
index 00000000..2dd9fd86
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/IntegerValueCell.cs
@@ -0,0 +1,39 @@
+#if UNITY_2019_4_OR_NEWER
+using System;
+
+namespace YooAsset.Editor
+{
+ public class IntegerValueCell : ITableCell, IComparable
+ {
+ public object CellValue { set; get; }
+ public string HeaderTitle { private set; get; }
+ public long IntegerValue
+ {
+ get
+ {
+ return (long)CellValue;
+ }
+ }
+
+ public IntegerValueCell(string headerTitle)
+ {
+ HeaderTitle = headerTitle;
+ }
+ public object GetDisplayObject()
+ {
+ return CellValue.ToString();
+ }
+ public int CompareTo(object other)
+ {
+ if (other is IntegerValueCell cell)
+ {
+ return this.IntegerValue.CompareTo(cell.IntegerValue);
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/IntegerValueCell.cs.meta b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/IntegerValueCell.cs.meta
new file mode 100644
index 00000000..8b47715e
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/IntegerValueCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: be8ecb3981efa744f89ee5d3c9e7b7ad
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/SingleValueCell.cs b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/SingleValueCell.cs
new file mode 100644
index 00000000..94508bc6
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/SingleValueCell.cs
@@ -0,0 +1,39 @@
+#if UNITY_2019_4_OR_NEWER
+using System;
+
+namespace YooAsset.Editor
+{
+ public class SingleValueCell : ITableCell, IComparable
+ {
+ public object CellValue { set; get; }
+ public string HeaderTitle { private set; get; }
+ public double SingleValue
+ {
+ get
+ {
+ return (double)CellValue;
+ }
+ }
+
+ public SingleValueCell(string headerTitle)
+ {
+ HeaderTitle = headerTitle;
+ }
+ public object GetDisplayObject()
+ {
+ return CellValue.ToString();
+ }
+ public int CompareTo(object other)
+ {
+ if (other is SingleValueCell cell)
+ {
+ return this.SingleValue.CompareTo(cell.SingleValue);
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/SingleValueCell.cs.meta b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/SingleValueCell.cs.meta
new file mode 100644
index 00000000..d4f4d2bd
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/SingleValueCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ae299b7a930e03f458977750de9ca18e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/StringValueCell.cs b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/StringValueCell.cs
new file mode 100644
index 00000000..eb6d4fbd
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/StringValueCell.cs
@@ -0,0 +1,39 @@
+#if UNITY_2019_4_OR_NEWER
+using System;
+
+namespace YooAsset.Editor
+{
+ public class StringValueCell : ITableCell, IComparable
+ {
+ public object CellValue { set; get; }
+ public string HeaderTitle { private set; get; }
+ public string StringValue
+ {
+ get
+ {
+ return (string)CellValue;
+ }
+ }
+
+ public StringValueCell(string headerTitle)
+ {
+ HeaderTitle = headerTitle;
+ }
+ public object GetDisplayObject()
+ {
+ return CellValue;
+ }
+ public int CompareTo(object other)
+ {
+ if (other is StringValueCell cell)
+ {
+ return this.StringValue.CompareTo(cell.StringValue);
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/StringValueCell.cs.meta b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/StringValueCell.cs.meta
new file mode 100644
index 00000000..5cf0d195
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/DefaultCells/StringValueCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a04fd2585c5538547b9755673aea76df
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/ITableCell.cs b/Assets/YooAsset/Editor/UIElements/TableView/ITableCell.cs
new file mode 100644
index 00000000..80a9ef2d
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/ITableCell.cs
@@ -0,0 +1,18 @@
+#if UNITY_2019_4_OR_NEWER
+
+namespace YooAsset.Editor
+{
+ public interface ITableCell
+ {
+ ///
+ /// 单元格数值
+ ///
+ object CellValue { set; get; }
+
+ ///
+ /// 获取界面显示对象
+ ///
+ object GetDisplayObject();
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/ITableCell.cs.meta b/Assets/YooAsset/Editor/UIElements/TableView/ITableCell.cs.meta
new file mode 100644
index 00000000..ca4c26c9
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/ITableCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: dcfa4e21884025c4b91db2efd543e139
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/ITableData.cs b/Assets/YooAsset/Editor/UIElements/TableView/ITableData.cs
new file mode 100644
index 00000000..fb48b3c7
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/ITableData.cs
@@ -0,0 +1,20 @@
+#if UNITY_2019_4_OR_NEWER
+using System;
+using System.Collections.Generic;
+
+namespace YooAsset.Editor
+{
+ public interface ITableData
+ {
+ ///
+ /// 是否可见
+ ///
+ bool Visible { set; get; }
+
+ ///
+ /// 单元格集合
+ ///
+ IList Cells { set; get; }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/ITableData.cs.meta b/Assets/YooAsset/Editor/UIElements/TableView/ITableData.cs.meta
new file mode 100644
index 00000000..6bb97bbf
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/ITableData.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 26779163e1da1ca46948287a4cc10023
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem.meta b/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem.meta
new file mode 100644
index 00000000..1d431dae
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 211ee819fabdd6d4399b79e6fcf45e5c
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/DefaultSearchSystem.cs b/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/DefaultSearchSystem.cs
new file mode 100644
index 00000000..1f3c1148
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/DefaultSearchSystem.cs
@@ -0,0 +1,229 @@
+#if UNITY_2019_4_OR_NEWER
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.RegularExpressions;
+using UnityEngine;
+
+namespace YooAsset.Editor
+{
+ public static class DefaultSearchSystem
+ {
+ ///
+ /// 解析搜索命令
+ ///
+ public static List ParseCommand(string commandContent)
+ {
+ if (string.IsNullOrEmpty(commandContent))
+ return new List();
+
+ List results = new List(10);
+ string[] commands = Regex.Split(commandContent, @"\s+");
+ foreach (var command in commands)
+ {
+ if (command.Contains("!="))
+ {
+ var splits = command.Split(new string[] { "!=" }, StringSplitOptions.None);
+ if (CheckSplitsValid(command, splits) == false)
+ continue;
+
+ var cmd = new SearchCompare();
+ cmd.HeaderTitle = splits[0];
+ cmd.CompareValue = splits[1];
+ cmd.CompareOperator = "!=";
+ results.Add(cmd);
+ }
+ else if (command.Contains(">="))
+ {
+ var splits = command.Split(new string[] { ">=" }, StringSplitOptions.None);
+ if (CheckSplitsValid(command, splits) == false)
+ continue;
+
+ var cmd = new SearchCompare();
+ cmd.HeaderTitle = splits[0];
+ cmd.CompareValue = splits[1];
+ cmd.CompareOperator = ">=";
+ results.Add(cmd);
+ }
+ else if (command.Contains("<="))
+ {
+ var splits = command.Split(new string[] { "<=" }, StringSplitOptions.None);
+ if (CheckSplitsValid(command, splits) == false)
+ continue;
+
+ var cmd = new SearchCompare();
+ cmd.HeaderTitle = splits[0];
+ cmd.CompareValue = splits[1];
+ cmd.CompareOperator = "<=";
+ results.Add(cmd);
+ }
+ else if (command.Contains(">"))
+ {
+ var splits = command.Split('>');
+ if (CheckSplitsValid(command, splits) == false)
+ continue;
+
+ var cmd = new SearchCompare();
+ cmd.HeaderTitle = splits[0];
+ cmd.CompareValue = splits[1];
+ cmd.CompareOperator = ">";
+ results.Add(cmd);
+ }
+ else if (command.Contains("<"))
+ {
+ var splits = command.Split('<');
+ if (CheckSplitsValid(command, splits) == false)
+ continue;
+
+ var cmd = new SearchCompare();
+ cmd.HeaderTitle = splits[0];
+ cmd.CompareValue = splits[1];
+ cmd.CompareOperator = "<";
+ results.Add(cmd);
+ }
+ else if (command.Contains("="))
+ {
+ var splits = command.Split('=');
+ if (CheckSplitsValid(command, splits) == false)
+ continue;
+
+ var cmd = new SearchCompare();
+ cmd.HeaderTitle = splits[0];
+ cmd.CompareValue = splits[1];
+ cmd.CompareOperator = "=";
+ results.Add(cmd);
+ }
+ else if (command.Contains(":"))
+ {
+ var splits = command.Split(':');
+ if (CheckSplitsValid(command, splits) == false)
+ continue;
+
+ var cmd = new SearchKeyword();
+ cmd.HeaderTitle = splits[0];
+ cmd.Keyword = splits[1];
+ results.Add(cmd);
+ }
+ else
+ {
+ var cmd = new SearchKeyword();
+ cmd.HeaderTitle = string.Empty;
+ cmd.Keyword = command;
+ results.Add(cmd);
+ }
+ }
+ return results;
+ }
+ private static bool CheckSplitsValid(string command, string[] splits)
+ {
+ if (splits.Length != 2)
+ {
+ Debug.LogWarning($"Invalid search command : {command}");
+ return false;
+ }
+
+ if (string.IsNullOrEmpty(splits[0]))
+ return false;
+ if (string.IsNullOrEmpty(splits[1]))
+ return false;
+
+ return true;
+ }
+
+ ///
+ /// 搜索匹配
+ ///
+ public static void Search(List sourceDatas, string command)
+ {
+ var searchCmds = ParseCommand(command);
+ foreach (var tableData in sourceDatas)
+ {
+ tableData.Visible = Search(tableData, searchCmds);
+ }
+ }
+ private static bool Search(ITableData tableData, List commands)
+ {
+ if (commands.Count == 0)
+ return true;
+
+ // 先匹配字符串
+ var searchKeywordCmds = commands.Where(cmd => cmd is SearchKeyword).ToList();
+ if (SearchKeyword(tableData, searchKeywordCmds) == false)
+ return false;
+
+ // 后匹配数值
+ var searchCompareCmds = commands.Where(cmd => cmd is SearchCompare).ToList();
+ if (SearchCompare(tableData, searchCompareCmds) == false)
+ return false;
+
+ return true;
+ }
+ private static bool SearchKeyword(ITableData tableData, List commands)
+ {
+ if (commands.Count == 0)
+ return true;
+
+ // 匹配规则:任意字符串列匹配成果
+ foreach (var tableCell in tableData.Cells)
+ {
+ foreach (var cmd in commands)
+ {
+ var searchKeywordCmd = cmd as SearchKeyword;
+ if (tableCell is StringValueCell stringValueCell)
+ {
+ if (string.IsNullOrEmpty(searchKeywordCmd.HeaderTitle) == false)
+ {
+ if (searchKeywordCmd.HeaderTitle == stringValueCell.HeaderTitle)
+ {
+ if (searchKeywordCmd.CompareTo(stringValueCell.StringValue))
+ return true;
+ }
+ }
+ else
+ {
+ if (searchKeywordCmd.CompareTo(stringValueCell.StringValue))
+ return true;
+ }
+ }
+ }
+ }
+
+ // 匹配失败
+ return false;
+ }
+ private static bool SearchCompare(ITableData tableData, List commands)
+ {
+ if (commands.Count == 0)
+ return true;
+
+ // 匹配规则:任意指定数值列匹配成果
+ foreach (var tableCell in tableData.Cells)
+ {
+ foreach (var cmd in commands)
+ {
+ var searchCompareCmd = cmd as SearchCompare;
+ if (tableCell is IntegerValueCell integerValueCell)
+ {
+ if (searchCompareCmd.HeaderTitle == integerValueCell.HeaderTitle)
+ {
+ if (searchCompareCmd.CompareTo(integerValueCell.IntegerValue))
+ return true;
+ }
+ }
+ else if (tableCell is SingleValueCell singleValueCell)
+ {
+ if (searchCompareCmd.HeaderTitle == singleValueCell.HeaderTitle)
+ {
+ if (searchCompareCmd.CompareTo(singleValueCell.SingleValue))
+ return true;
+ }
+ }
+ }
+ }
+
+ // 匹配失败
+ return false;
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/DefaultSearchSystem.cs.meta b/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/DefaultSearchSystem.cs.meta
new file mode 100644
index 00000000..05c21007
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/DefaultSearchSystem.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3de1e93052c2c86408ba77125da962cd
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/ISearchCommand.cs b/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/ISearchCommand.cs
new file mode 100644
index 00000000..b3bd1945
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/ISearchCommand.cs
@@ -0,0 +1,9 @@
+#if UNITY_2019_4_OR_NEWER
+
+namespace YooAsset.Editor
+{
+ public interface ISearchCommand
+ {
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/ISearchCommand.cs.meta b/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/ISearchCommand.cs.meta
new file mode 100644
index 00000000..01ceb9c6
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/ISearchCommand.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4228528e243224045863d8ae14a16194
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/SearchCompare.cs b/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/SearchCompare.cs
new file mode 100644
index 00000000..41502957
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/SearchCompare.cs
@@ -0,0 +1,133 @@
+#if UNITY_2019_4_OR_NEWER
+using System;
+using UnityEditor;
+using UnityEngine;
+
+namespace YooAsset.Editor
+{
+ ///
+ /// 指定标题的比较搜索
+ ///
+ public class SearchCompare : ISearchCommand
+ {
+ public string HeaderTitle;
+ public string CompareValue;
+ public string CompareOperator;
+
+ ///
+ /// 转换的整形数值
+ ///
+ private bool _isConvertedIntegerNum = false;
+ private long _convertedIntegerNumber = 0;
+ public long IntegerNumberValue
+ {
+ get
+ {
+ if (_isConvertedIntegerNum == false)
+ {
+ _isConvertedIntegerNum = true;
+ _convertedIntegerNumber = long.Parse(CompareValue.ToString());
+ }
+ return _convertedIntegerNumber;
+ }
+ }
+
+ ///
+ /// 转换的浮点数值
+ ///
+ private bool _isConvertedSingleNum = false;
+ private double _convertedSingleNumber = 0;
+ public double SingleNumberValue
+ {
+ get
+ {
+ if (_isConvertedSingleNum == false)
+ {
+ _isConvertedSingleNum = true;
+ _convertedSingleNumber = double.Parse(CompareValue.ToString());
+ }
+ return _convertedSingleNumber;
+ }
+ }
+
+ public bool CompareTo(long value)
+ {
+ if (CompareOperator == ">")
+ {
+ if (value > SingleNumberValue)
+ return true;
+ }
+ else if (CompareOperator == ">=")
+ {
+ if (value >= SingleNumberValue)
+ return true;
+ }
+ else if (CompareOperator == "<")
+ {
+ if (value < SingleNumberValue)
+ return true;
+ }
+ else if (CompareOperator == "<=")
+ {
+ if (value <= SingleNumberValue)
+ return true;
+ }
+ else if (CompareOperator == "=")
+ {
+ if (value == SingleNumberValue)
+ return true;
+ }
+ else if (CompareOperator == "!=")
+ {
+ if (value != SingleNumberValue)
+ return true;
+ }
+ else
+ {
+ Debug.LogWarning($"Can not support operator : {CompareOperator}");
+ }
+
+ return false;
+ }
+ public bool CompareTo(double value)
+ {
+ if (CompareOperator == ">")
+ {
+ if (value > IntegerNumberValue)
+ return true;
+ }
+ else if (CompareOperator == ">=")
+ {
+ if (value >= IntegerNumberValue)
+ return true;
+ }
+ else if (CompareOperator == "<")
+ {
+ if (value < IntegerNumberValue)
+ return true;
+ }
+ else if (CompareOperator == "<=")
+ {
+ if (value <= IntegerNumberValue)
+ return true;
+ }
+ else if (CompareOperator == "=")
+ {
+ if (value == IntegerNumberValue)
+ return true;
+ }
+ else if (CompareOperator == "!=")
+ {
+ if (value != IntegerNumberValue)
+ return true;
+ }
+ else
+ {
+ Debug.LogWarning($"Can not support operator : {CompareOperator}");
+ }
+
+ return false;
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/SearchCompare.cs.meta b/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/SearchCompare.cs.meta
new file mode 100644
index 00000000..38340f6e
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/SearchCompare.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 345cafa16ea7ccc488c96af1a4ca33c2
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/SearchKeyword.cs b/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/SearchKeyword.cs
new file mode 100644
index 00000000..2fefc758
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/SearchKeyword.cs
@@ -0,0 +1,19 @@
+#if UNITY_2019_4_OR_NEWER
+
+namespace YooAsset.Editor
+{
+ ///
+ /// 搜索关键字
+ ///
+ public class SearchKeyword : ISearchCommand
+ {
+ public string HeaderTitle;
+ public string Keyword;
+
+ public bool CompareTo(string value)
+ {
+ return value.Contains(Keyword);
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/SearchKeyword.cs.meta b/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/SearchKeyword.cs.meta
new file mode 100644
index 00000000..fe3f4d7f
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/SearchSystem/SearchKeyword.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3c34fa79e35e66247b64f18eafa1d230
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/TableColumn.cs b/Assets/YooAsset/Editor/UIElements/TableView/TableColumn.cs
new file mode 100644
index 00000000..aada90ef
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/TableColumn.cs
@@ -0,0 +1,50 @@
+#if UNITY_2019_4_OR_NEWER
+using System;
+using UnityEditor;
+using UnityEngine;
+using UnityEditor.UIElements;
+using UnityEngine.UIElements;
+
+namespace YooAsset.Editor
+{
+ public class TableColumn
+ {
+ ///
+ /// 单元列索引值
+ ///
+ internal int ColumnIndex;
+
+ ///
+ /// UI元素名称
+ ///
+ public string ElementName { private set; get; }
+
+ ///
+ /// 标题名称
+ ///
+ public string HeaderTitle { private set; get; }
+
+ ///
+ /// 单元列样式
+ ///
+ public ColumnStyle ColumnStyle { private set; get; }
+
+ ///
+ /// 制作单元格元素
+ ///
+ public Func MakeCell;
+
+ ///
+ /// 绑定数据到单元格
+ ///
+ public Action BindCell;
+
+ public TableColumn(string elementName, string headerTitle, ColumnStyle columnStyle)
+ {
+ this.ElementName = elementName;
+ this.HeaderTitle = headerTitle;
+ this.ColumnStyle = columnStyle;
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/TableColumn.cs.meta b/Assets/YooAsset/Editor/UIElements/TableView/TableColumn.cs.meta
new file mode 100644
index 00000000..f7abec1e
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/TableColumn.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 034395dad363e3a4da96881de60918a3
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/TableView.cs b/Assets/YooAsset/Editor/UIElements/TableView/TableView.cs
new file mode 100644
index 00000000..96f9bdda
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/TableView.cs
@@ -0,0 +1,245 @@
+#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 TableView : VisualElement
+ {
+ private readonly Toolbar _toolbar;
+ private readonly ListView _listView;
+
+ private readonly List _columns = new List(10);
+ private List _itemsSource;
+ private List _sortingDatas;
+
+ // 排序相关
+ private string _sortingHeaderElement = string.Empty;
+ private bool _descendingSort = true;
+
+ ///
+ /// 数据源
+ ///
+ public List itemsSource
+ {
+ get
+ {
+ return _itemsSource;
+ }
+ set
+ {
+ if (CheckItemsSource(value))
+ {
+ _itemsSource = value;
+ _sortingDatas = value;
+ }
+ }
+ }
+
+ ///
+ /// 单元视图交互事件
+ ///
+ public Action ClickTableDataEvent;
+
+ ///
+ /// 单元视图交互事件
+ ///
+ public Action ClickTableHeadEvent;
+
+
+ public TableView()
+ {
+ _toolbar = new Toolbar();
+ this.Add(_toolbar);
+
+ _listView = new ListView();
+ _listView.makeItem = MakeListViewElement;
+ _listView.bindItem = BindListViewElement;
+ _listView.RegisterCallback(OnClickListItem);
+ this.Add(_listView);
+ }
+
+ ///
+ /// 添加单元列
+ ///
+ public void AddColumn(TableColumn column)
+ {
+ var toolbarBtn = new ToolbarButton();
+ toolbarBtn.userData = column;
+ toolbarBtn.name = column.ElementName;
+ toolbarBtn.text = column.HeaderTitle;
+ toolbarBtn.style.unityTextAlign = TextAnchor.MiddleLeft;
+ toolbarBtn.style.flexGrow = column.ColumnStyle.Stretchable ? 1f : 0f;
+ toolbarBtn.style.width = column.ColumnStyle.Width;
+ toolbarBtn.style.minWidth = column.ColumnStyle.MinWidth;
+ toolbarBtn.style.maxWidth = column.ColumnStyle.MaxWidth;
+ toolbarBtn.clickable.clickedWithEventInfo += OnClickTableHead;
+ SetCellElementStyle(toolbarBtn);
+ _toolbar.Add(toolbarBtn);
+ _columns.Add(column);
+
+ // 计算索引值
+ 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();
+ }
+
+ private bool CheckItemsSource(List itemsSource)
+ {
+ if (itemsSource == null || itemsSource.Count == 0)
+ {
+ Debug.LogWarning("Items source is null or empty !");
+ return false;
+ }
+
+ 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 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 (_sortingHeaderElement != clickedColumn.ElementName)
+ {
+ _sortingHeaderElement = clickedColumn.ElementName;
+ _descendingSort = false;
+ }
+ else
+ {
+ _descendingSort = !_descendingSort;
+ }
+
+ // 升降符号
+ foreach (var column in _columns)
+ {
+ var button = _toolbar.Q(column.ElementName);
+ button.text = column.HeaderTitle;
+ }
+ if (_descendingSort)
+ toolbarBtn.text = $"{clickedColumn.HeaderTitle} ↓";
+ else
+ toolbarBtn.text = $"{clickedColumn.HeaderTitle} ↑";
+
+ // 升降排序
+ if (_descendingSort)
+ _sortingDatas = _itemsSource.OrderByDescending(tableData => tableData.Cells[clickedColumn.ColumnIndex]).ToList();
+ else
+ _sortingDatas = _itemsSource.OrderBy(tableData => tableData.Cells[clickedColumn.ColumnIndex]).ToList();
+
+ // 刷新数据表
+ RebuildView();
+ }
+ private VisualElement MakeListViewElement()
+ {
+ VisualElement listViewElement = new VisualElement();
+ listViewElement.style.flexDirection = FlexDirection.Row;
+ foreach (var colum in _columns)
+ {
+ var cellElement = colum.MakeCell.Invoke();
+ cellElement.name = colum.ElementName;
+ SetCellElementStyle(cellElement);
+ listViewElement.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.paddingLeft = defaultStyle;
+ element.style.paddingRight = defaultStyle;
+ element.style.marginTop = defaultStyle;
+ element.style.marginBottom = defaultStyle;
+ element.style.marginLeft = defaultStyle;
+ element.style.marginRight = defaultStyle;
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/YooAsset/Editor/UIElements/TableView/TableView.cs.meta b/Assets/YooAsset/Editor/UIElements/TableView/TableView.cs.meta
new file mode 100644
index 00000000..6519b589
--- /dev/null
+++ b/Assets/YooAsset/Editor/UIElements/TableView/TableView.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9c12f27850c4d104db1dc85cf532e586
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant: