diff --git a/Editor/MenuExtension/MenuExtension.cs b/Editor/MenuExtension/MenuExtension.cs index e20d9ce..c4cb927 100644 --- a/Editor/MenuExtension/MenuExtension.cs +++ b/Editor/MenuExtension/MenuExtension.cs @@ -6,20 +6,32 @@ namespace AlicizaX.UI.Extension.Editor { internal static class MenuExtension { - [MenuItem("GameObject/UI/UXTextMeshPro", false, -1)] - static void CreateUXTextMeshProUX() + [MenuItem("GameObject/UX/UXTextMeshPro", false, -1)] + private static void CreateUxTextMeshProUx() { GameObject selectionObject = Selection.activeGameObject; var gameObject = new GameObject("UXTextMeshPro", typeof(UXTextMeshPro)); gameObject.transform.SetParent(selectionObject.transform); var rectTransform = gameObject.GetComponent(); var uxTextMeshPro = gameObject.GetComponent(); - uxTextMeshPro.text="UXTextMeshPro"; + uxTextMeshPro.text = "UXTextMeshPro"; rectTransform.anchoredPosition = Vector2.zero; rectTransform.localPosition = Vector3.zero; rectTransform.pivot = new Vector2(0.5f, 0.5f); rectTransform.localScale = Vector3.one; Selection.activeGameObject = gameObject; } + + [MenuItem("GameObject/UX/RecyclerView", false, -1)] + private static void CreateUxRecyclerView() + { + GameObject selectionObject = Selection.activeGameObject; + if (selectionObject == null) return; + const string prefabPath = "Packages/com.alicizax.unity.ui.extension/Editor/RecyclerView/Res/ScrollView.prefab"; + GameObject prefab = AssetDatabase.LoadAssetAtPath(prefabPath); + GameObject instance = (GameObject)PrefabUtility.InstantiatePrefab(prefab, selectionObject.transform); + PrefabUtility.UnpackPrefabInstance(instance, PrefabUnpackMode.Completely, InteractionMode.UserAction); + Selection.activeGameObject = instance; + } } } diff --git a/Editor/RecyclerView.meta b/Editor/RecyclerView.meta new file mode 100644 index 0000000..0abfca9 --- /dev/null +++ b/Editor/RecyclerView.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2856fb53117f4988b9585025859c4075 +timeCreated: 1748497429 \ No newline at end of file diff --git a/Editor/RecyclerView/RecyclerViewEditor.cs b/Editor/RecyclerView/RecyclerViewEditor.cs new file mode 100644 index 0000000..66bbbf5 --- /dev/null +++ b/Editor/RecyclerView/RecyclerViewEditor.cs @@ -0,0 +1,472 @@ +using UnityEditor; +using UnityEngine; +using System; +using System.Collections.Generic; +using System.Linq; +using AlicizaX.UI.RecyclerView; +using UnityEngine.UI; +using Object = UnityEngine.Object; + +[CustomEditor(typeof(RecyclerView))] +public class RecyclerViewEditor : Editor +{ + // Layout Manager + private SerializedProperty _layoutManagerTypeName; + private SerializedProperty _layoutManager; + private List _layoutTypeNames = new List(); + private int _selectedLayoutIndex; + + // Scroller + private SerializedProperty scroll; + private SerializedProperty _scroller; + private SerializedProperty _scrollerTypeName; + private List _scrollerTypes = new List(); + private List _scrollerTypeNames; + private int _selectedScrollerIndex; + + // Base Properties + private SerializedProperty direction; + private SerializedProperty alignment; + private SerializedProperty content; + private SerializedProperty spacing; + private SerializedProperty padding; + private SerializedProperty snap; + private SerializedProperty scrollSpeed; + private SerializedProperty wheelSpeed; + private SerializedProperty templates; + + private SerializedProperty _showScrollBar; + private SerializedProperty _scrollbar; + + private const string NoneOptionName = "None"; + + private void OnEnable() + { + // Layout Manager + _layoutManagerTypeName = serializedObject.FindProperty("_layoutManagerTypeName"); + _layoutManager = serializedObject.FindProperty("_layoutManager"); + RefreshLayoutTypes(); + + // Scroller + scroll = serializedObject.FindProperty("scroll"); + _scroller = serializedObject.FindProperty("_scroller"); + _scrollerTypeName = serializedObject.FindProperty("_scrollerTypeName"); + RefreshScrollerTypes(); + SyncExistingScroller(); + + // Base Properties + direction = serializedObject.FindProperty("direction"); + alignment = serializedObject.FindProperty("alignment"); + content = serializedObject.FindProperty("content"); + spacing = serializedObject.FindProperty("spacing"); + padding = serializedObject.FindProperty("padding"); + snap = serializedObject.FindProperty("snap"); + scrollSpeed = serializedObject.FindProperty("scrollSpeed"); + wheelSpeed = serializedObject.FindProperty("wheelSpeed"); + templates = serializedObject.FindProperty("templates"); + _showScrollBar = serializedObject.FindProperty("_showScrollBar"); + _scrollbar = serializedObject.FindProperty("_scrollbar"); + } + + #region Layout Manager + + void RefreshLayoutTypes() + { + _layoutTypeNames.Clear(); + _layoutTypeNames.Add(NoneOptionName); + + // 获取所有实现ILayoutManager的非Mono类型 + var types = AlicizaX.Utility.Assembly.GetRuntimeTypes(typeof(ILayoutManager)); + foreach (var type in types) + { + if (!typeof(MonoBehaviour).IsAssignableFrom(type)) + { + _layoutTypeNames.Add(type.FullName); + } + } + + _selectedLayoutIndex = Mathf.Clamp( + _layoutTypeNames.IndexOf(_layoutManagerTypeName.stringValue), + 0, + _layoutTypeNames.Count - 1 + ); + } + + #endregion + + #region Scroller + + void RefreshScrollerTypes() + { + _scrollerTypes = TypeCache.GetTypesDerivedFrom() + .Where(t => t.IsSubclassOf(typeof(MonoBehaviour))) + .ToList(); + + _scrollerTypeNames = _scrollerTypes + .Select(t => t.FullName) + .Prepend(NoneOptionName) + .ToList(); + } + + void SyncExistingScroller() + { + var rv = target as RecyclerView; + if (rv == null) return; + + var existing = rv.GetComponent(); + if (existing != null) + { + _scrollerTypeName.stringValue = existing.GetType().FullName; + _selectedScrollerIndex = _scrollerTypeNames.IndexOf(_scrollerTypeName.stringValue); + } + else + { + _selectedScrollerIndex = 0; + } + } + + #endregion + + public override void OnInspectorGUI() + { + serializedObject.Update(); + bool isPlaying = Application.isPlaying; + + DrawLayoutManagerSection(isPlaying); + DrawBaseSettings(isPlaying); + DrawScrollerSettings(isPlaying); + DrawTemplatesSection(); + + serializedObject.ApplyModifiedProperties(); + } + + #region Drawing Methods + + void DrawLayoutManagerSection(bool isPlaying) + { + EditorGUILayout.BeginVertical("box"); + { + EditorGUILayout.LabelField("Layout Manager", EditorStyles.boldLabel); + + using (new EditorGUI.DisabledScope(isPlaying)) + { + // 强制允许选择空值 + int newIndex = EditorGUILayout.Popup("Layout Type", _selectedLayoutIndex, _layoutTypeNames.ToArray()); + if (newIndex != _selectedLayoutIndex) + { + _selectedLayoutIndex = newIndex; // 立即更新索引 + UpdateLayoutManager(newIndex); + } + } + + // 显示布局属性或警告 + if (_layoutManager.managedReferenceValue != null) + { + EditorGUILayout.Space(3); + DrawManagedProperties(_layoutManager); + } + else + { + EditorGUILayout.HelpBox("Need Choose LayoutManager", MessageType.Error); + } + } + EditorGUILayout.EndVertical(); + } + + void DrawBaseSettings(bool isPlaying) + { + EditorGUILayout.BeginVertical("box"); + { + EditorGUILayout.LabelField("Base Settings", EditorStyles.boldLabel); + + using (new EditorGUI.DisabledScope(isPlaying)) + { + EditorGUILayout.PropertyField(direction); + EditorGUILayout.PropertyField(alignment); + EditorGUILayout.PropertyField(content); + } + + EditorGUILayout.Space(5); + EditorGUILayout.LabelField("Spacing", EditorStyles.boldLabel); + EditorGUILayout.PropertyField(spacing); + EditorGUILayout.PropertyField(padding); + + EditorGUILayout.Space(5); + EditorGUILayout.LabelField("Scrolling", EditorStyles.boldLabel); + + using (new EditorGUI.DisabledScope(isPlaying)) + { + bool prevScrollValue = scroll.boolValue; + EditorGUILayout.PropertyField(scroll); + + if (scroll.boolValue != prevScrollValue) + { + HandleScrollToggle(); + if (!scroll.boolValue) + { + ClearScrollBar(); + } + } + } + + if (scroll.boolValue) + { + using (new EditorGUI.DisabledScope(isPlaying)) + { + bool prevShowScrollBarValue = _showScrollBar.boolValue; + EditorGUILayout.PropertyField(_showScrollBar); + + if (_showScrollBar.boolValue != prevShowScrollBarValue) + { + HandleScrollBarToggle(); + } + } + } + + + EditorGUILayout.PropertyField(snap); + } + EditorGUILayout.EndVertical(); + } + + void DrawScrollerSettings(bool isPlaying) + { + if (!scroll.boolValue) return; + + EditorGUILayout.BeginVertical("box"); + { + EditorGUILayout.LabelField("Scroller Settings", EditorStyles.boldLabel); + + using (new EditorGUI.DisabledScope(isPlaying)) + { + int newIndex = EditorGUILayout.Popup("Scroller Type", _selectedScrollerIndex, _scrollerTypeNames.ToArray()); + if (newIndex != _selectedScrollerIndex) + { + UpdateScroller(newIndex); + } + } + + var rv = target as RecyclerView; + if (rv != null) + { + var scrollerComponent = rv.GetComponent(); + if (scrollerComponent != null) + { + DrawComponentProperties(scrollerComponent as MonoBehaviour, "Scroller Properties"); + } + else + { + EditorGUILayout.HelpBox("Must choose to use a Scroller.", MessageType.Error); + } + } + + EditorGUILayout.Space(3); + EditorGUILayout.PropertyField(scrollSpeed); + EditorGUILayout.PropertyField(wheelSpeed); + } + EditorGUILayout.EndVertical(); + } + + void DrawComponentProperties(MonoBehaviour component, string header = null) + { + if (component == null) return; + + EditorGUILayout.Space(3); + if (!string.IsNullOrEmpty(header)) + { + EditorGUILayout.LabelField(header, EditorStyles.boldLabel); + } + + SerializedObject so = new SerializedObject(component); + so.Update(); + + SerializedProperty prop = so.GetIterator(); + bool enterChildren = true; + while (prop.NextVisible(enterChildren)) + { + enterChildren = false; + if (prop.name == "m_Script") continue; + EditorGUILayout.PropertyField(prop, true); + } + + so.ApplyModifiedProperties(); + } + + void DrawTemplatesSection() + { + EditorGUILayout.Space(5); + EditorGUILayout.PropertyField(templates, new GUIContent("Item Templates"), true); + } + + #endregion + + #region Update Handlers + + void UpdateLayoutManager(int selectedIndex) + { + try + { + // 强制清空逻辑 + if (selectedIndex == 0) + { + _layoutManager.managedReferenceValue = null; + _layoutManagerTypeName.stringValue = ""; + _selectedLayoutIndex = 0; // 确保索引同步 + return; + } + + // 有效性检查 + if (selectedIndex < 0 || selectedIndex >= _layoutTypeNames.Count) + { + Debug.LogError($"Invalid layout index: {selectedIndex}"); + _selectedLayoutIndex = 0; + return; + } + + string typeName = _layoutTypeNames[selectedIndex]; + Type type = AlicizaX.Utility.Assembly.GetType(typeName); + + if (type != null && typeof(ILayoutManager).IsAssignableFrom(type)) + { + _layoutManager.managedReferenceValue = Activator.CreateInstance(type); + _layoutManagerTypeName.stringValue = typeName; + _selectedLayoutIndex = selectedIndex; + } + else + { + Debug.LogError($"Invalid layout type: {typeName}"); + _selectedLayoutIndex = 0; + } + } + catch (Exception e) + { + Debug.LogError($"Layout Manager Error: {e.Message}"); + _layoutManager.managedReferenceValue = null; + _layoutManagerTypeName.stringValue = ""; + _selectedLayoutIndex = 0; + } + } + + void UpdateScroller(int selectedIndex) + { + try + { + var rv = target as RecyclerView; + if (rv == null) return; + + Undo.RecordObjects(new UnityEngine.Object[] { rv, this }, "Update Scroller"); + + // 移除旧组件 + var oldScroller = rv.GetComponent(); + if (oldScroller != null) + { + Undo.DestroyObjectImmediate(oldScroller as MonoBehaviour); + } + + if (selectedIndex == 0) + { + // 清除序列化引用 + _scroller.objectReferenceValue = null; + _scrollerTypeName.stringValue = ""; + return; + } + + // 添加新组件 + Type selectedType = _scrollerTypes[selectedIndex - 1]; + var newScroller = Undo.AddComponent(rv.gameObject, selectedType) as IScroller; + + // 同步到序列化属性 + _scroller.objectReferenceValue = newScroller as MonoBehaviour; + _scrollerTypeName.stringValue = selectedType.FullName; + _selectedScrollerIndex = selectedIndex; + + // 立即应用修改 + serializedObject.ApplyModifiedProperties(); + EditorUtility.SetDirty(rv); // 标记对象需要保存 + } + catch (Exception e) + { + Debug.LogError($"Scroller Error: {e}"); + _selectedScrollerIndex = 0; + _scrollerTypeName.stringValue = ""; + _scroller.objectReferenceValue = null; + } + } + + void HandleScrollToggle() + { + var rv = target as RecyclerView; + if (rv == null) return; + + if (!scroll.boolValue) + { + // Remove scroller component + var scrollerComponent = rv.GetComponent(); + if (scrollerComponent != null) + { + Undo.DestroyObjectImmediate(scrollerComponent as MonoBehaviour); + } + + _scrollerTypeName.stringValue = ""; + _selectedScrollerIndex = 0; + } + } + + void HandleScrollBarToggle() + { + var rv = target as RecyclerView; + if (rv == null) return; + if (_showScrollBar.boolValue) + { + Direction direction = (Direction)alignment.enumValueIndex; + if (direction == Direction.Vertical) + { + const string path = "Packages/com.alicizax.unity.ui.extension/Editor/RecyclerView/Res/vertical.prefab"; + InstantiateScrollBar(path, rv.transform); + } + else if (direction == Direction.Horizontal) + { + const string path = "Packages/com.alicizax.unity.ui.extension/Editor/RecyclerView/Res/horizontal.prefab"; + InstantiateScrollBar(path, rv.transform); + } + } + else + { + ClearScrollBar(); + } + } + + void ClearScrollBar() + { + _showScrollBar.boolValue = false; + if (_scrollbar.objectReferenceValue != null) + { + Scrollbar scrollbar = _scrollbar.objectReferenceValue as Scrollbar; + _scrollbar.objectReferenceValue = null; + Object.DestroyImmediate(scrollbar.gameObject); + } + } + + #endregion + + void DrawManagedProperties(SerializedProperty property) + { + SerializedProperty iterator = property.Copy(); + bool enterChildren = true; + + while (iterator.NextVisible(enterChildren)) + { + enterChildren = false; + if (iterator.name == "m_Script") continue; + EditorGUILayout.PropertyField(iterator, true); + } + } + + void InstantiateScrollBar(string path, Transform parent) + { + GameObject prefab = AssetDatabase.LoadAssetAtPath(path); + GameObject instance = (GameObject)PrefabUtility.InstantiatePrefab(prefab, parent); + PrefabUtility.UnpackPrefabInstance(instance, PrefabUnpackMode.Completely, InteractionMode.UserAction); + _scrollbar.objectReferenceValue = instance.GetComponent(); + } +} diff --git a/Editor/RecyclerView/RecyclerViewEditor.cs.meta b/Editor/RecyclerView/RecyclerViewEditor.cs.meta new file mode 100644 index 0000000..720bbd4 --- /dev/null +++ b/Editor/RecyclerView/RecyclerViewEditor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a05527bf8840412aa310698d13cb3196 +timeCreated: 1748497433 \ No newline at end of file diff --git a/Editor/RecyclerView/Res.meta b/Editor/RecyclerView/Res.meta new file mode 100644 index 0000000..451e4d2 --- /dev/null +++ b/Editor/RecyclerView/Res.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4491d5adb2174f42907cd6bd579711ef +timeCreated: 1748503337 \ No newline at end of file diff --git a/Editor/RecyclerView/Res/ScrollView.prefab b/Editor/RecyclerView/Res/ScrollView.prefab new file mode 100644 index 0000000..dc7e40a --- /dev/null +++ b/Editor/RecyclerView/Res/ScrollView.prefab @@ -0,0 +1,176 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1235572201494389031 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 953826052447570581} + - component: {fileID: 409256563818501030} + - component: {fileID: 4967247000384896254} + - component: {fileID: 2527097672867102998} + - component: {fileID: 144409482669617178} + m_Layer: 5 + m_Name: ScrollView + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &953826052447570581 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1235572201494389031} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7227160576944475251} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 250, y: 400} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &409256563818501030 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1235572201494389031} + m_CullTransparentMesh: 1 +--- !u!114 &4967247000384896254 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1235572201494389031} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.6886792, g: 0.6886792, b: 0.6886792, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &2527097672867102998 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1235572201494389031} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7efd8e83d2092b347952108134dc37eb, type: 3} + m_Name: + m_EditorClassIdentifier: + direction: 1 + alignment: 1 + content: {fileID: 7227160576944475251} + spacing: {x: 0, y: 0} + padding: {x: 0, y: 0} + scroll: 1 + snap: 0 + scrollSpeed: 10 + wheelSpeed: 30 + templates: [] + _scrollerTypeName: AlicizaX.UI.RecyclerView.Scroller + _scroller: {fileID: 144409482669617178} + _layoutManagerTypeName: AlicizaX.UI.RecyclerView.LinearLayoutManager + _layoutManager: + rid: 6528754475160043629 + references: + version: 2 + RefIds: + - rid: 6528754475160043629 + type: {class: LinearLayoutManager, ns: AlicizaX.UI.RecyclerView, asm: AlicizaX.UI.Extension} + data: + testValue: 0 +--- !u!114 &144409482669617178 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1235572201494389031} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7b7de4cb3a1546e4a9ade6b8dbf8af92, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &9220717789715235424 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7227160576944475251} + - component: {fileID: 2326586106184642263} + m_Layer: 5 + m_Name: Content + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7227160576944475251 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9220717789715235424} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 953826052447570581} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2326586106184642263 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9220717789715235424} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3312d7739989d2b4e91e6319e9a96d76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: {x: 0, y: 0, z: 0, w: 0} + m_Softness: {x: 0, y: 0} diff --git a/Editor/RecyclerView/Res/ScrollView.prefab.meta b/Editor/RecyclerView/Res/ScrollView.prefab.meta new file mode 100644 index 0000000..4258166 --- /dev/null +++ b/Editor/RecyclerView/Res/ScrollView.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4ed07b7776718d548804a6d7b5539205 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/RecyclerView/Res/horizontal.prefab b/Editor/RecyclerView/Res/horizontal.prefab new file mode 100644 index 0000000..08b4be3 --- /dev/null +++ b/Editor/RecyclerView/Res/horizontal.prefab @@ -0,0 +1,252 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &2002449542824361868 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 488252331187428264} + - component: {fileID: 2101354351137448834} + - component: {fileID: 8235216341801835209} + - component: {fileID: 8283467313266023839} + - component: {fileID: 3358419500410988058} + m_Layer: 0 + m_Name: horizontal + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &488252331187428264 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2002449542824361868} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7124834573134617791} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -40, y: 10} + m_Pivot: {x: 0.5, y: 0} +--- !u!222 &2101354351137448834 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2002449542824361868} + m_CullTransparentMesh: 1 +--- !u!114 &8235216341801835209 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2002449542824361868} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.3773585, g: 0.3773585, b: 0.3773585, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &8283467313266023839 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2002449542824361868} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 2326542036480137540} + m_HandleRect: {fileID: 193229221570547880} + m_Direction: 0 + m_Value: 0 + m_Size: 0.4 + m_NumberOfSteps: 0 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &3358419500410988058 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2002449542824361868} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 682cfe39b0fffe544be8d5c11eb369e5, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &4575532730663240958 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 193229221570547880} + - component: {fileID: 1924433296360427437} + - component: {fileID: 2326542036480137540} + m_Layer: 0 + m_Name: Handle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &193229221570547880 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4575532730663240958} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 7124834573134617791} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1924433296360427437 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4575532730663240958} + m_CullTransparentMesh: 1 +--- !u!114 &2326542036480137540 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4575532730663240958} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &6761444411709800685 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7124834573134617791} + m_Layer: 0 + m_Name: SlidingArea + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7124834573134617791 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6761444411709800685} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 193229221570547880} + m_Father: {fileID: 488252331187428264} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} diff --git a/Editor/RecyclerView/Res/horizontal.prefab.meta b/Editor/RecyclerView/Res/horizontal.prefab.meta new file mode 100644 index 0000000..21915df --- /dev/null +++ b/Editor/RecyclerView/Res/horizontal.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 98998c9d3c2263646be3f24d0996a493 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/RecyclerView/Res/vertical.prefab b/Editor/RecyclerView/Res/vertical.prefab new file mode 100644 index 0000000..634af2a --- /dev/null +++ b/Editor/RecyclerView/Res/vertical.prefab @@ -0,0 +1,252 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &220331575378582965 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7591792402052135596} + - component: {fileID: 2150618277400837422} + - component: {fileID: 3952935497572886421} + - component: {fileID: 2116943976852970174} + - component: {fileID: 4776801802864796469} + m_Layer: 5 + m_Name: vertical + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7591792402052135596 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 220331575378582965} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 6760799037446078325} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 10, y: 0} + m_Pivot: {x: 0.5, y: 0} +--- !u!222 &2150618277400837422 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 220331575378582965} + m_CullTransparentMesh: 1 +--- !u!114 &3952935497572886421 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 220331575378582965} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.3207547, g: 0.3207547, b: 0.3207547, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &2116943976852970174 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 220331575378582965} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 2198892040955573086} + m_HandleRect: {fileID: 2839511060116175760} + m_Direction: 3 + m_Value: 0 + m_Size: 0.2 + m_NumberOfSteps: 0 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &4776801802864796469 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 220331575378582965} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 682cfe39b0fffe544be8d5c11eb369e5, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &2110970298716295489 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2839511060116175760} + - component: {fileID: 1084884340137269109} + - component: {fileID: 2198892040955573086} + m_Layer: 5 + m_Name: Handle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2839511060116175760 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2110970298716295489} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6760799037446078325} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1084884340137269109 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2110970298716295489} + m_CullTransparentMesh: 1 +--- !u!114 &2198892040955573086 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2110970298716295489} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &8790787763373649645 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6760799037446078325} + m_Layer: 5 + m_Name: Sliding Area + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6760799037446078325 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8790787763373649645} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 2839511060116175760} + m_Father: {fileID: 7591792402052135596} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -20, y: -20} + m_Pivot: {x: 0.5, y: 0.5} diff --git a/Editor/RecyclerView/Res/vertical.prefab.meta b/Editor/RecyclerView/Res/vertical.prefab.meta new file mode 100644 index 0000000..691f727 --- /dev/null +++ b/Editor/RecyclerView/Res/vertical.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e657950d0fd9fd443a1cb9d16c3fa86e +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Res/Scroll-view.png b/Editor/Res/Scroll-view.png new file mode 100644 index 0000000..c255dd9 Binary files /dev/null and b/Editor/Res/Scroll-view.png differ diff --git a/Editor/Res/Scroll-view.png.meta b/Editor/Res/Scroll-view.png.meta new file mode 100644 index 0000000..1f32768 --- /dev/null +++ b/Editor/Res/Scroll-view.png.meta @@ -0,0 +1,117 @@ +fileFormatVersion: 2 +guid: a01ce47da31a2e0438fd8d38b203c0d5 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 0 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/RecyclerView/Adapter/Adapter.cs b/Runtime/RecyclerView/Adapter/Adapter.cs index 019fbe9..bea7917 100644 --- a/Runtime/RecyclerView/Adapter/Adapter.cs +++ b/Runtime/RecyclerView/Adapter/Adapter.cs @@ -33,8 +33,6 @@ namespace AlicizaX.UI.RecyclerView this.recyclerView = recyclerView; this.list = list; this.onItemClick = onItemClick; - - this.recyclerView.Adapter = this; } public virtual int GetItemCount() diff --git a/Runtime/RecyclerView/Layout/CircleLayoutManager.cs b/Runtime/RecyclerView/Layout/CircleLayoutManager.cs index aedbb94..341d533 100644 --- a/Runtime/RecyclerView/Layout/CircleLayoutManager.cs +++ b/Runtime/RecyclerView/Layout/CircleLayoutManager.cs @@ -6,24 +6,20 @@ namespace AlicizaX.UI.RecyclerView public class CircleLayoutManager : LayoutManager { private float radius; - private new CircleDirection direction; private float intervalAngle; + + private new CircleDirection direction; + [SerializeField] private float initalAngle; - public override RecyclerView RecyclerView - { - get => recyclerView; - set - { - recyclerView = value; - recyclerView.SetScroller(recyclerView.gameObject.AddComponent()); - } - } - public CircleLayoutManager(CircleDirection direction = CircleDirection.Positive, float initalAngle = 0) + public CircleLayoutManager(CircleDirection direction = CircleDirection.Positive) { this.direction = direction; - this.initalAngle = initalAngle; + } + + public CircleLayoutManager() + { } public override Vector2 CalculateContentSize() diff --git a/Runtime/RecyclerView/Layout/GridLayoutManager.cs b/Runtime/RecyclerView/Layout/GridLayoutManager.cs index aa34f4f..2b22e4c 100644 --- a/Runtime/RecyclerView/Layout/GridLayoutManager.cs +++ b/Runtime/RecyclerView/Layout/GridLayoutManager.cs @@ -6,6 +6,11 @@ namespace AlicizaX.UI.RecyclerView { private Vector2 cellSize; + public GridLayoutManager() + { + + } + public GridLayoutManager(int unit = 1) { this.unit = unit; @@ -59,6 +64,7 @@ namespace AlicizaX.UI.RecyclerView width = viewportSize.x; height = viewportSize.y; } + return new Vector2((width - cellSize.x) / 2, (height - cellSize.y) / 2); } @@ -75,6 +81,7 @@ namespace AlicizaX.UI.RecyclerView width = viewportSize.x; height = viewportSize.y; } + return new Vector2((width - cellSize.x) / 2, (height - cellSize.y) / 2); } diff --git a/Runtime/RecyclerView/Layout/LayoutManager.cs b/Runtime/RecyclerView/Layout/LayoutManager.cs index c5949d6..8082587 100644 --- a/Runtime/RecyclerView/Layout/LayoutManager.cs +++ b/Runtime/RecyclerView/Layout/LayoutManager.cs @@ -1,7 +1,9 @@ +using System; using UnityEngine; namespace AlicizaX.UI.RecyclerView { + [Serializable] public abstract class LayoutManager : ILayoutManager { protected Vector2 viewportSize; diff --git a/Runtime/RecyclerView/Layout/PageLayoutManager.cs b/Runtime/RecyclerView/Layout/PageLayoutManager.cs index d1348a4..c7cada9 100644 --- a/Runtime/RecyclerView/Layout/PageLayoutManager.cs +++ b/Runtime/RecyclerView/Layout/PageLayoutManager.cs @@ -6,11 +6,11 @@ namespace AlicizaX.UI.RecyclerView { public class PageLayoutManager : LinearLayoutManager { + [SerializeField] private float minScale; - public PageLayoutManager(float minScale = 0.9f) + public PageLayoutManager() { - this.minScale = minScale; } public override Vector2 CalculateContentSize() @@ -26,6 +26,7 @@ namespace AlicizaX.UI.RecyclerView position += viewportSize.y - lineHeight; return new Vector2(contentSize.x, position + padding.y * 2); } + position = index * (lineHeight + spacing.x) - spacing.x; position += viewportSize.x - lineHeight; return new Vector2(position + padding.x * 2, contentSize.y); @@ -39,6 +40,7 @@ namespace AlicizaX.UI.RecyclerView position = index * (lineHeight + spacing.y) - ScrollPosition; return new Vector2(0, position + padding.y); } + position = index * (lineHeight + spacing.x) - ScrollPosition; return new Vector2(position + padding.x, 0); } @@ -74,9 +76,7 @@ namespace AlicizaX.UI.RecyclerView List viewHolders = viewProvider.ViewHolders; for (int i = 0; i < viewHolders.Count; i++) { - float viewPos = direction == Direction.Vertical ? - -viewHolders[i].RectTransform.anchoredPosition.y : - viewHolders[i].RectTransform.anchoredPosition.x; + float viewPos = direction == Direction.Vertical ? -viewHolders[i].RectTransform.anchoredPosition.y : viewHolders[i].RectTransform.anchoredPosition.x; float scale = 1 - Mathf.Min(Mathf.Abs(viewPos) * 0.0006f, 1f); scale = Mathf.Max(scale, minScale); diff --git a/Runtime/RecyclerView/RecyclerView.cs b/Runtime/RecyclerView/RecyclerView.cs index 89c9aa8..cb7df79 100644 --- a/Runtime/RecyclerView/RecyclerView.cs +++ b/Runtime/RecyclerView/RecyclerView.cs @@ -1,5 +1,6 @@ using System; using UnityEngine; +using UnityEngine.Serialization; using UnityEngine.UI; namespace AlicizaX.UI.RecyclerView @@ -93,10 +94,21 @@ namespace AlicizaX.UI.RecyclerView set => templates = value; } + + [SerializeField] private string _scrollerTypeName; + + [SerializeReference] private Scroller _scroller; + + [SerializeField] private bool _showScrollBar; + [SerializeReference] private Scrollbar _scrollbar; + + private ViewProvider viewProvider; - private LayoutManager layoutManager; - private Scroller scroller; - private Scrollbar scrollbar; + + [SerializeField] private string _layoutManagerTypeName; + + [SerializeReference] private LayoutManager _layoutManager; + private int startIndex, endIndex; private int currentIndex; @@ -119,73 +131,40 @@ namespace AlicizaX.UI.RecyclerView } } - public Scroller Scroller - { - get - { - if (scroller == null) - { - if (scroll) - { - scroller = gameObject.AddComponent(); - ConfigScroller(); - } - } - return scroller; - } - } + public Scrollbar Scrollbar => _scrollbar; - public Scrollbar Scrollbar - { - get - { - if (scrollbar == null) - { - scrollbar = GetComponentInChildren(); - if (scrollbar != null) - { - scrollbar.gameObject.SetActive(scroll); - scrollbar.onValueChanged.AddListener(OnScrollbarChanged); - scrollbar.gameObject.AddComponent().OnDragEnd = OnScrollbarDragEnd; - } - } + private IAdapter Adapter; - return scrollbar; - } - } - - public IAdapter Adapter { get; set; } - - public LayoutManager LayoutManager => layoutManager; + public LayoutManager LayoutManager => _layoutManager; public Action OnIndexChanged; public Action OnScrollValueChanged; private void OnValidate() { - if (scroller != null) + if (_scroller != null) { - scroller.ScrollSpeed = scrollSpeed; - scroller.WheelSpeed = wheelSpeed; + _scroller.ScrollSpeed = scrollSpeed; + _scroller.WheelSpeed = wheelSpeed; } } private void OnScrollChanged(float pos) { - layoutManager.UpdateLayout(); + _layoutManager.UpdateLayout(); if (Scrollbar != null) { - Scrollbar.SetValueWithoutNotify(pos / Scroller.MaxPosition); + Scrollbar.SetValueWithoutNotify(pos / _scroller.MaxPosition); } - if (layoutManager.IsFullInvisibleStart(startIndex)) + if (_layoutManager.IsFullInvisibleStart(startIndex)) { viewProvider.RemoveViewHolder(startIndex); - startIndex += layoutManager.Unit; + startIndex += _layoutManager.Unit; } - else if (layoutManager.IsFullVisibleStart(startIndex)) + else if (_layoutManager.IsFullVisibleStart(startIndex)) { if (startIndex == 0) { @@ -193,36 +172,36 @@ namespace AlicizaX.UI.RecyclerView } else { - startIndex -= layoutManager.Unit; + startIndex -= _layoutManager.Unit; viewProvider.CreateViewHolder(startIndex); } } - if (layoutManager.IsFullInvisibleEnd(endIndex)) + if (_layoutManager.IsFullInvisibleEnd(endIndex)) { viewProvider.RemoveViewHolder(endIndex); - endIndex -= layoutManager.Unit; + endIndex -= _layoutManager.Unit; } - else if (layoutManager.IsFullVisibleEnd(endIndex)) + else if (_layoutManager.IsFullVisibleEnd(endIndex)) { - if (endIndex >= viewProvider.GetItemCount() - layoutManager.Unit) + if (endIndex >= viewProvider.GetItemCount() - _layoutManager.Unit) { // TODO Do something, eg: Load More } else { - endIndex += layoutManager.Unit; + endIndex += _layoutManager.Unit; viewProvider.CreateViewHolder(endIndex); } } // 使用滚动条快速定位时,刷新整个列表 - if (!layoutManager.IsVisible(startIndex) || !layoutManager.IsVisible(endIndex)) + if (!_layoutManager.IsVisible(startIndex) || !_layoutManager.IsVisible(endIndex)) { Refresh(); } - layoutManager.DoItemAnimation(); + _layoutManager.DoItemAnimation(); OnScrollValueChanged?.Invoke(); } @@ -237,12 +216,12 @@ namespace AlicizaX.UI.RecyclerView private void OnScrollbarChanged(float ratio) { - Scroller.ScrollToRatio(ratio); + _scroller.ScrollToRatio(ratio); } private void OnScrollbarDragEnd() { - if (Scroller.Position < Scroller.MaxPosition) + if (_scroller.Position < _scroller.MaxPosition) { if (Snap) { @@ -257,6 +236,9 @@ namespace AlicizaX.UI.RecyclerView { templates[i].gameObject.SetActive(false); } + + ConfigScroller(); + ConfigScrollbar(); } private void OnDestroy() @@ -267,86 +249,84 @@ namespace AlicizaX.UI.RecyclerView public void Reset() { viewProvider?.Reset(); - if (scroller != null) + if (_scroller != null) { - scroller.Position = 0; + _scroller.Position = 0; } - if (scrollbar != null) + if (_scrollbar != null) { - scrollbar.SetValueWithoutNotify(0); + _scrollbar.SetValueWithoutNotify(0); } } - public void SetLayoutManager(LayoutManager layoutManager) + public void SetAdapter(IAdapter adapter) { - this.layoutManager = layoutManager; - + Adapter = adapter; ViewProvider.Adapter = Adapter; - ViewProvider.LayoutManager = layoutManager; - - this.layoutManager.RecyclerView = this; - this.layoutManager.Adapter = Adapter; - this.layoutManager.ViewProvider = viewProvider; - this.layoutManager.Direction = direction; - this.layoutManager.Alignment = alignment; - this.layoutManager.Spacing = spacing; - this.layoutManager.Padding = padding; - this.layoutManager.CanScroll = CanScroll; + ViewProvider.LayoutManager = _layoutManager; + ViewProvider.LayoutManager = _layoutManager; + _layoutManager.RecyclerView = this; + _layoutManager.Adapter = Adapter; + _layoutManager.ViewProvider = viewProvider; + _layoutManager.Direction = direction; + _layoutManager.Alignment = alignment; + _layoutManager.Spacing = spacing; + _layoutManager.Padding = padding; + _layoutManager.CanScroll = CanScroll; } - public void SetScroller(Scroller newScroller) - { - if (!scroll) return; - - if (scroller != null) - { - scroller.OnValueChanged.RemoveListener(OnScrollChanged); - scroller.OnMoveStoped.RemoveListener(OnMoveStoped); - Destroy(scroller); - } - - scroller = newScroller; - ConfigScroller(); - } private void ConfigScroller() { - scroller.ScrollSpeed = scrollSpeed; - scroller.WheelSpeed = wheelSpeed; - scroller.Snap = Snap; - scroller.OnValueChanged.AddListener(OnScrollChanged); - scroller.OnMoveStoped.AddListener(OnMoveStoped); + if (_scroller != null) + { + _scroller.ScrollSpeed = scrollSpeed; + _scroller.WheelSpeed = wheelSpeed; + _scroller.Snap = Snap; + _scroller.OnValueChanged.AddListener(OnScrollChanged); + _scroller.OnMoveStoped.AddListener(OnMoveStoped); + } + } + + private void ConfigScrollbar() + { + if (_showScrollBar && _scrollbar != null) + { + _scrollbar.gameObject.SetActive(scroll); + _scrollbar.onValueChanged.AddListener(OnScrollbarChanged); + _scrollbar.gameObject.AddComponent().OnDragEnd = OnScrollbarDragEnd; + } } public void Refresh() { ViewProvider.Clear(); - startIndex = layoutManager.GetStartIndex(); - endIndex = layoutManager.GetEndIndex(); - for (int i = startIndex; i <= endIndex; i += layoutManager.Unit) + startIndex = _layoutManager.GetStartIndex(); + endIndex = _layoutManager.GetEndIndex(); + for (int i = startIndex; i <= endIndex; i += _layoutManager.Unit) { ViewProvider.CreateViewHolder(i); } - layoutManager.DoItemAnimation(); + _layoutManager.DoItemAnimation(); } public void RequestLayout() { - layoutManager.SetContentSize(); + _layoutManager.SetContentSize(); - if (Scroller == null) return; + if (_scroller == null) return; - Scroller.Direction = direction; - Scroller.ViewSize = layoutManager.ViewportSize; - Scroller.ContentSize = layoutManager.ContentSize; + _scroller.Direction = direction; + _scroller.ViewSize = _layoutManager.ViewportSize; + _scroller.ContentSize = _layoutManager.ContentSize; - if (Scrollbar != null && Scroller.ContentSize != Vector2.zero) + if (Scrollbar != null && _scroller.ContentSize != Vector2.zero) { - if ((direction == Direction.Vertical && layoutManager.ContentSize.y <= layoutManager.ViewportSize.y) || - (direction == Direction.Horizontal && layoutManager.ContentSize.x <= layoutManager.ViewportSize.x) || + if ((direction == Direction.Vertical && _layoutManager.ContentSize.y <= _layoutManager.ViewportSize.y) || + (direction == Direction.Horizontal && _layoutManager.ContentSize.x <= _layoutManager.ViewportSize.x) || (direction == Direction.Custom)) { Scrollbar.gameObject.SetActive(false); @@ -355,21 +335,21 @@ namespace AlicizaX.UI.RecyclerView { Scrollbar.gameObject.SetActive(true); Scrollbar.direction = direction == Direction.Vertical ? Scrollbar.Direction.TopToBottom : Scrollbar.Direction.LeftToRight; - Scrollbar.size = direction == Direction.Vertical ? Scroller.ViewSize.y / Scroller.ContentSize.y : Scroller.ViewSize.x / Scroller.ContentSize.x; + Scrollbar.size = direction == Direction.Vertical ? _scroller.ViewSize.y / _scroller.ContentSize.y : _scroller.ViewSize.x / _scroller.ContentSize.x; } } } public float GetScrollPosition() { - return Scroller ? Scroller.Position : 0; + return _scroller ? _scroller.Position : 0; } public void ScrollTo(int index, bool smooth = false) { if (!scroll) return; - Scroller.ScrollTo(layoutManager.IndexToPosition(index), smooth); + _scroller.ScrollTo(_layoutManager.IndexToPosition(index), smooth); if (!smooth) { Refresh(); @@ -387,7 +367,7 @@ namespace AlicizaX.UI.RecyclerView private void SnapTo() { - var index = layoutManager.PositionToIndex(GetScrollPosition()); + var index = _layoutManager.PositionToIndex(GetScrollPosition()); ScrollTo(index, true); } } diff --git a/Runtime/RecyclerView/RecyclerView.cs.meta b/Runtime/RecyclerView/RecyclerView.cs.meta index a7f6e1c..6bbf25a 100644 --- a/Runtime/RecyclerView/RecyclerView.cs.meta +++ b/Runtime/RecyclerView/RecyclerView.cs.meta @@ -5,7 +5,7 @@ MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 - icon: {instanceID: 0} + icon: {fileID: 2800000, guid: a01ce47da31a2e0438fd8d38b203c0d5, type: 3} userData: assetBundleName: assetBundleVariant: diff --git a/Runtime/RecyclerView/Scroller/CircleScroller.cs b/Runtime/RecyclerView/Scroller/CircleScroller.cs index 336e374..7273e1e 100644 --- a/Runtime/RecyclerView/Scroller/CircleScroller.cs +++ b/Runtime/RecyclerView/Scroller/CircleScroller.cs @@ -1,8 +1,10 @@ +using System; using UnityEngine; using UnityEngine.EventSystems; namespace AlicizaX.UI.RecyclerView { + [Serializable] public class CircleScroller : Scroller { private Vector2 centerPosition; diff --git a/Runtime/RecyclerView/Scroller/Scroller.cs b/Runtime/RecyclerView/Scroller/Scroller.cs index 1349b4f..d619133 100644 --- a/Runtime/RecyclerView/Scroller/Scroller.cs +++ b/Runtime/RecyclerView/Scroller/Scroller.cs @@ -1,9 +1,11 @@ +using System; using System.Collections; using UnityEngine; using UnityEngine.EventSystems; namespace AlicizaX.UI.RecyclerView { + [Serializable] public class Scroller : MonoBehaviour, IScroller, IBeginDragHandler, IEndDragHandler, IDragHandler, IScrollHandler { protected float position;