From 656e0b0652cdde8ad2810e45927c2469dd2cf743 Mon Sep 17 00:00:00 2001 From: TongZiGang <754383023@qq.com> Date: Sat, 19 Jul 2025 17:59:28 +0800 Subject: [PATCH] =?UTF-8?q?=E8=99=9A=E6=8B=9F=E5=88=97=E8=A1=A8=E5=92=8C?= =?UTF-8?q?=E5=BE=AA=E7=8E=AF=E5=88=97=E8=A1=A8=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Tools/AssetBundle/AssetBundleManager.cs | 50 +- .../Assets/Scripts/GameLogic/UI/UIManager.cs | 2 +- .../Assets/Scripts/ThirdParty/LoopList.meta | 8 + .../Scripts/ThirdParty/LoopList/Editor.meta | 8 + .../Editor/LoopScrollRectInspector.cs | 311 +++ .../Editor/LoopScrollRectInspector.cs.meta | 12 + .../LoopList/Editor/SGDefaultControls.cs | 182 ++ .../LoopList/Editor/SGDefaultControls.cs.meta | 12 + .../LoopList/Editor/SGMenuOptions.cs | 151 ++ .../LoopList/Editor/SGMenuOptions.cs.meta | 12 + .../Scripts/ThirdParty/LoopList/Runtime.meta | 8 + .../Runtime/LoopHorizontalScrollRect.cs | 188 ++ .../Runtime/LoopHorizontalScrollRect.cs.meta | 12 + .../Runtime/LoopHorizontalScrollRectMulti.cs | 188 ++ .../LoopHorizontalScrollRectMulti.cs.meta | 12 + .../LoopList/Runtime/LoopScrollDataSource.cs | 10 + .../Runtime/LoopScrollDataSource.cs.meta | 12 + .../Runtime/LoopScrollMultiDataSource.cs | 10 + .../Runtime/LoopScrollMultiDataSource.cs.meta | 12 + .../Runtime/LoopScrollPrefabSource.cs | 12 + .../Runtime/LoopScrollPrefabSource.cs.meta | 12 + .../LoopList/Runtime/LoopScrollRect.cs | 76 + .../LoopList/Runtime/LoopScrollRect.cs.meta | 12 + .../LoopList/Runtime/LoopScrollRectBase.cs | 2401 +++++++++++++++++ .../Runtime/LoopScrollRectBase.cs.meta | 12 + .../LoopList/Runtime/LoopScrollRectMulti.cs | 56 + .../Runtime/LoopScrollRectMulti.cs.meta | 11 + .../LoopList/Runtime/LoopScrollSizeHelper.cs | 11 + .../Runtime/LoopScrollSizeHelper.cs.meta | 12 + .../LoopList/Runtime/LoopScrollSizeUtils.cs | 38 + .../Runtime/LoopScrollSizeUtils.cs.meta | 3 + .../Runtime/LoopVerticalScrollRect.cs | 188 ++ .../Runtime/LoopVerticalScrollRect.cs.meta | 12 + .../Runtime/LoopVerticalScrollRectMulti.cs | 187 ++ .../LoopVerticalScrollRectMulti.cs.meta | 12 + .../Scripts/ThirdParty/LoopList/UILoopList.cs | 135 + .../ThirdParty/LoopList/UILoopList.cs.meta | 3 + .../UserSettings/Layouts/default-2022.dwlt | 66 +- 38 files changed, 4420 insertions(+), 39 deletions(-) create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList.meta create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor.meta create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/LoopScrollRectInspector.cs create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/LoopScrollRectInspector.cs.meta create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/SGDefaultControls.cs create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/SGDefaultControls.cs.meta create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/SGMenuOptions.cs create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/SGMenuOptions.cs.meta create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime.meta create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopHorizontalScrollRect.cs create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopHorizontalScrollRect.cs.meta create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopHorizontalScrollRectMulti.cs create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopHorizontalScrollRectMulti.cs.meta create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollDataSource.cs create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollDataSource.cs.meta create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollMultiDataSource.cs create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollMultiDataSource.cs.meta create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollPrefabSource.cs create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollPrefabSource.cs.meta create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRect.cs create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRect.cs.meta create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRectBase.cs create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRectBase.cs.meta create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRectMulti.cs create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRectMulti.cs.meta create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollSizeHelper.cs create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollSizeHelper.cs.meta create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollSizeUtils.cs create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollSizeUtils.cs.meta create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopVerticalScrollRect.cs create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopVerticalScrollRect.cs.meta create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopVerticalScrollRectMulti.cs create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopVerticalScrollRectMulti.cs.meta create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/UILoopList.cs create mode 100644 UnityGame/Assets/Scripts/ThirdParty/LoopList/UILoopList.cs.meta diff --git a/UnityGame/Assets/Scripts/GameLogic/Tools/AssetBundle/AssetBundleManager.cs b/UnityGame/Assets/Scripts/GameLogic/Tools/AssetBundle/AssetBundleManager.cs index 90bd5a0..d1f9d81 100644 --- a/UnityGame/Assets/Scripts/GameLogic/Tools/AssetBundle/AssetBundleManager.cs +++ b/UnityGame/Assets/Scripts/GameLogic/Tools/AssetBundle/AssetBundleManager.cs @@ -71,8 +71,12 @@ namespace CreatGame.AssetBundle IsInitializeAsync = true; } } - - public void LoadGameObject(string assetBundleName, Action callback) + /// + /// 异步加载资源 + /// + /// + /// + public void LoadGameObjectAsync(string assetBundleName, Action callback) { if (assetBundles.TryGetValue(assetBundleName, out var bundle)) { @@ -84,9 +88,9 @@ namespace CreatGame.AssetBundle { if (handle.Status == AsyncOperationStatus.Succeeded) { - var asset = handle.Result; - assetBundles.Add(assetBundleName, new AssetBundleData { assetBundleName = assetBundleName, assetBundle = asset }); - callback?.Invoke(GameObject.Instantiate(asset)); + var assetData = CacheAssetBundles(assetBundleName, handle.Result); + Addressables.Release(handle); + callback?.Invoke(GameObject.Instantiate(assetData.assetBundle)); } else { @@ -95,5 +99,41 @@ namespace CreatGame.AssetBundle } }; } + /// + /// 同步等待加载资源 + /// + /// + public GameObject LoadGameObject(string assetBundleName) + { + if (assetBundles.TryGetValue(assetBundleName, out var bundle)) + { + return GameObject.Instantiate(bundle.assetBundle); + } + + var handle = Addressables.LoadAssetAsync(assetBundleName); + handle.WaitForCompletion(); + if (handle.Status == AsyncOperationStatus.Succeeded) + { + bundle = CacheAssetBundles(assetBundleName, handle.Result); + Addressables.Release(handle); + + return GameObject.Instantiate(bundle.assetBundle); + } + + Debug.LogError("资源加载失败"); + return null; + } + /// + /// 缓存加载出来的资源 + /// + /// + /// + /// + private AssetBundleData CacheAssetBundles(string bundleName, GameObject bundle = null) + { + var data = new AssetBundleData(){assetBundleName = bundleName, assetBundle = GameObject.Instantiate(bundle)}; + assetBundles.Add(bundleName, data); + return data; + } } } \ No newline at end of file diff --git a/UnityGame/Assets/Scripts/GameLogic/UI/UIManager.cs b/UnityGame/Assets/Scripts/GameLogic/UI/UIManager.cs index b7faf4d..09d1626 100644 --- a/UnityGame/Assets/Scripts/GameLogic/UI/UIManager.cs +++ b/UnityGame/Assets/Scripts/GameLogic/UI/UIManager.cs @@ -52,7 +52,7 @@ namespace CreatGame.UI { var view = new T(); //加载预制件 - AssetBundleManager.Instance.LoadGameObject(view.PrefabPath, (obj) => + AssetBundleManager.Instance.LoadGameObjectAsync(view.PrefabPath, (obj) => { if (obj == null) { diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList.meta b/UnityGame/Assets/Scripts/ThirdParty/LoopList.meta new file mode 100644 index 0000000..3fffc93 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 42130aa0870f6df4bb6217cc2e5805c3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor.meta b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor.meta new file mode 100644 index 0000000..71910ea --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b10ceda9bec25b14ea5e190eb9bb0341 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/LoopScrollRectInspector.cs b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/LoopScrollRectInspector.cs new file mode 100644 index 0000000..87db9e8 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/LoopScrollRectInspector.cs @@ -0,0 +1,311 @@ +using UnityEditor; +using UnityEditor.AnimatedValues; +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.UIElements; + +namespace UnityEditor.UI +{ + [CustomEditor(typeof(LoopScrollRectBase), true)] + public class LoopScrollRectInspector : Editor + { + SerializedProperty m_Content; + SerializedProperty m_Horizontal; + SerializedProperty m_Vertical; + SerializedProperty m_MovementType; + SerializedProperty m_Elasticity; + SerializedProperty m_Inertia; + SerializedProperty m_DecelerationRate; + SerializedProperty m_ScrollSensitivity; + SerializedProperty m_Viewport; + SerializedProperty m_HorizontalScrollbar; + SerializedProperty m_VerticalScrollbar; + SerializedProperty m_HorizontalScrollbarVisibility; + SerializedProperty m_VerticalScrollbarVisibility; + SerializedProperty m_HorizontalScrollbarSpacing; + SerializedProperty m_VerticalScrollbarSpacing; + SerializedProperty m_OnValueChanged; + AnimBool m_ShowElasticity; + AnimBool m_ShowDecelerationRate; + bool m_ViewportIsNotChild, m_HScrollbarIsNotChild, m_VScrollbarIsNotChild; + static string s_HError = "For this visibility mode, the Viewport property and the Horizontal Scrollbar property both needs to be set to a Rect Transform that is a child to the Scroll Rect."; + static string s_VError = "For this visibility mode, the Viewport property and the Vertical Scrollbar property both needs to be set to a Rect Transform that is a child to the Scroll Rect."; + + //==========LoopScrollRect========== + SerializedProperty totalCount; + SerializedProperty reverseDirection; + + int firstItem = 0, lastItem = 0, scrollIndex = 0; + float firstOffset = 0.0f, lastOffset = 0.0f, scrollOffset = 0; + LoopScrollRectBase.ScrollMode scrollMode = LoopScrollRectBase.ScrollMode.ToStart; + float scrollSpeed = 1000, scrollTime = 1; + + protected virtual void OnEnable() + { + m_Content = serializedObject.FindProperty("m_Content"); + m_Horizontal = serializedObject.FindProperty("m_Horizontal"); + m_Vertical = serializedObject.FindProperty("m_Vertical"); + m_MovementType = serializedObject.FindProperty("m_MovementType"); + m_Elasticity = serializedObject.FindProperty("m_Elasticity"); + m_Inertia = serializedObject.FindProperty("m_Inertia"); + m_DecelerationRate = serializedObject.FindProperty("m_DecelerationRate"); + m_ScrollSensitivity = serializedObject.FindProperty("m_ScrollSensitivity"); + m_Viewport = serializedObject.FindProperty("m_Viewport"); + m_HorizontalScrollbar = serializedObject.FindProperty("m_HorizontalScrollbar"); + m_VerticalScrollbar = serializedObject.FindProperty("m_VerticalScrollbar"); + m_HorizontalScrollbarVisibility = serializedObject.FindProperty("m_HorizontalScrollbarVisibility"); + m_VerticalScrollbarVisibility = serializedObject.FindProperty("m_VerticalScrollbarVisibility"); + m_HorizontalScrollbarSpacing = serializedObject.FindProperty("m_HorizontalScrollbarSpacing"); + m_VerticalScrollbarSpacing = serializedObject.FindProperty("m_VerticalScrollbarSpacing"); + m_OnValueChanged = serializedObject.FindProperty("m_OnValueChanged"); + + m_ShowElasticity = new AnimBool(Repaint); + m_ShowDecelerationRate = new AnimBool(Repaint); + SetAnimBools(true); + + //==========LoopScrollRect========== + totalCount = serializedObject.FindProperty("totalCount"); + reverseDirection = serializedObject.FindProperty("reverseDirection"); + } + + protected virtual void OnDisable() + { + m_ShowElasticity.valueChanged.RemoveListener(Repaint); + m_ShowDecelerationRate.valueChanged.RemoveListener(Repaint); + } + + void SetAnimBools(bool instant) + { + SetAnimBool(m_ShowElasticity, !m_MovementType.hasMultipleDifferentValues && m_MovementType.enumValueIndex == (int)ScrollRect.MovementType.Elastic, instant); + SetAnimBool(m_ShowDecelerationRate, !m_Inertia.hasMultipleDifferentValues && m_Inertia.boolValue == true, instant); + } + + void SetAnimBool(AnimBool a, bool value, bool instant) + { + if (instant) + a.value = value; + else + a.target = value; + } + + void CalculateCachedValues() + { + m_ViewportIsNotChild = false; + m_HScrollbarIsNotChild = false; + m_VScrollbarIsNotChild = false; + if (targets.Length == 1) + { + Transform transform = ((LoopScrollRectBase)target).transform; + if (m_Viewport.objectReferenceValue == null || ((RectTransform)m_Viewport.objectReferenceValue).transform.parent != transform) + m_ViewportIsNotChild = true; + if (m_HorizontalScrollbar.objectReferenceValue == null || ((Scrollbar)m_HorizontalScrollbar.objectReferenceValue).transform.parent != transform) + m_HScrollbarIsNotChild = true; + if (m_VerticalScrollbar.objectReferenceValue == null || ((Scrollbar)m_VerticalScrollbar.objectReferenceValue).transform.parent != transform) + m_VScrollbarIsNotChild = true; + } + } + + public override void OnInspectorGUI() + { + SetAnimBools(false); + + serializedObject.Update(); + // Once we have a reliable way to know if the object changed, only re-cache in that case. + CalculateCachedValues(); + + EditorGUILayout.LabelField("Scroll Rect", EditorStyles.boldLabel); + EditorGUILayout.PropertyField(m_Content); + + EditorGUILayout.PropertyField(m_Horizontal); + EditorGUILayout.PropertyField(m_Vertical); + + EditorGUILayout.PropertyField(m_MovementType); + if (EditorGUILayout.BeginFadeGroup(m_ShowElasticity.faded)) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_Elasticity); + EditorGUI.indentLevel--; + } + EditorGUILayout.EndFadeGroup(); + + EditorGUILayout.PropertyField(m_Inertia); + if (EditorGUILayout.BeginFadeGroup(m_ShowDecelerationRate.faded)) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_DecelerationRate); + EditorGUI.indentLevel--; + } + EditorGUILayout.EndFadeGroup(); + + EditorGUILayout.PropertyField(m_ScrollSensitivity); + + EditorGUILayout.Space(); + + EditorGUILayout.PropertyField(m_Viewport); + + EditorGUILayout.PropertyField(m_HorizontalScrollbar); + if (m_HorizontalScrollbar.objectReferenceValue && !m_HorizontalScrollbar.hasMultipleDifferentValues) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_HorizontalScrollbarVisibility, EditorGUIUtility.TrTextContent("Visibility")); + + if ((ScrollRect.ScrollbarVisibility)m_HorizontalScrollbarVisibility.enumValueIndex == ScrollRect.ScrollbarVisibility.AutoHideAndExpandViewport + && !m_HorizontalScrollbarVisibility.hasMultipleDifferentValues) + { + if (m_ViewportIsNotChild || m_HScrollbarIsNotChild) + EditorGUILayout.HelpBox(s_HError, MessageType.Error); + EditorGUILayout.PropertyField(m_HorizontalScrollbarSpacing, EditorGUIUtility.TrTextContent("Spacing")); + } + + EditorGUI.indentLevel--; + } + + EditorGUILayout.PropertyField(m_VerticalScrollbar); + if (m_VerticalScrollbar.objectReferenceValue && !m_VerticalScrollbar.hasMultipleDifferentValues) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(m_VerticalScrollbarVisibility, EditorGUIUtility.TrTextContent("Visibility")); + + if ((ScrollRect.ScrollbarVisibility)m_VerticalScrollbarVisibility.enumValueIndex == ScrollRect.ScrollbarVisibility.AutoHideAndExpandViewport + && !m_VerticalScrollbarVisibility.hasMultipleDifferentValues) + { + if (m_ViewportIsNotChild || m_VScrollbarIsNotChild) + EditorGUILayout.HelpBox(s_VError, MessageType.Error); + EditorGUILayout.PropertyField(m_VerticalScrollbarSpacing, EditorGUIUtility.TrTextContent("Spacing")); + } + + EditorGUI.indentLevel--; + } + + EditorGUILayout.PropertyField(m_OnValueChanged); + + //==========LoopScrollRect========== + EditorGUILayout.LabelField("Loop Scroll Rect", EditorStyles.boldLabel); + EditorGUILayout.PropertyField(totalCount); + EditorGUILayout.PropertyField(reverseDirection); + + serializedObject.ApplyModifiedProperties(); + + LoopScrollRectBase scroll = (LoopScrollRectBase)target; + GUI.enabled = Application.isPlaying; + const float buttonWidth = 100f; + + #region Basic Test + EditorGUILayout.LabelField("Basic Test", EditorStyles.boldLabel); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Clear existing items"); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Clear", GUILayout.Width(buttonWidth))) + { + scroll.ClearCells(); + } + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Refresh existing items(only update data)"); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Refresh", GUILayout.Width(buttonWidth))) + { + scroll.RefreshCells(); + } + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Refill(0, 0.0f)"); + GUILayout.FlexibleSpace(); + if(GUILayout.Button("Refill", GUILayout.Width(buttonWidth))) + { + scroll.RefillCells(); + } + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("RefillFromEnd(0, 0.0f)"); + GUILayout.FlexibleSpace(); + if(GUILayout.Button("RefillFromEnd", GUILayout.Width(buttonWidth))) + { + scroll.RefillCellsFromEnd(); + } + EditorGUILayout.EndHorizontal(); + #endregion + + #region Refill Test + EditorGUILayout.LabelField("Refill Test", EditorStyles.boldLabel); + + firstItem = EditorGUILayout.IntField("FirstItem", firstItem); + firstOffset = EditorGUILayout.FloatField("FirstOffset", firstOffset); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Get first item and offset"); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("GetFirstItem", GUILayout.Width(buttonWidth))) + { + firstItem = scroll.GetFirstItem(out firstOffset); + } + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Refill with first item and offset"); + GUILayout.FlexibleSpace(); + if(GUILayout.Button("Refill", GUILayout.Width(buttonWidth))) + { + scroll.RefillCells(scroll.reverseDirection ? (scroll.totalCount - firstItem) : firstItem, firstOffset); + } + EditorGUILayout.EndHorizontal(); + #endregion + + #region Refill Test + EditorGUILayout.LabelField("RefillFromEnd Test", EditorStyles.boldLabel); + + lastItem = EditorGUILayout.IntField("LastItem", lastItem); + lastOffset = EditorGUILayout.FloatField("LastOffset", lastOffset); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Get last item and offset"); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("GetLastItem", GUILayout.Width(buttonWidth))) + { + lastItem = scroll.GetLastItem(out lastOffset); + } + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("RefillFromEnd with last item and offset"); + GUILayout.FlexibleSpace(); + if(GUILayout.Button("RefillFromEnd", GUILayout.Width(buttonWidth))) + { + scroll.RefillCellsFromEnd(scroll.reverseDirection ? lastItem : (scroll.totalCount - lastItem), lastOffset); + } + EditorGUILayout.EndHorizontal(); + #endregion + + #region Scroll Test + EditorGUILayout.LabelField("Scroll Test", EditorStyles.boldLabel); + scrollIndex = EditorGUILayout.IntField("ScrollIndex", scrollIndex); + scrollOffset = EditorGUILayout.FloatField("ScrollOffset", scrollOffset); + scrollMode = (LoopScrollRectBase.ScrollMode)EditorGUILayout.EnumPopup("Mode", scrollMode); + + scrollSpeed = EditorGUILayout.FloatField("Speed", scrollSpeed); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Scroll to index and offset with speed"); + GUILayout.FlexibleSpace(); + if(GUILayout.Button("ScrollToCell", GUILayout.Width(buttonWidth))) + { + scroll.ScrollToCell(scrollIndex, scrollSpeed, scrollOffset, scrollMode); + } + EditorGUILayout.EndHorizontal(); + + scrollTime = EditorGUILayout.FloatField("Time", scrollTime); + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Scroll to index and offset whtin time"); + GUILayout.FlexibleSpace(); + if(GUILayout.Button("ScrollToCellWithinTime", GUILayout.Width(buttonWidth))) + { + scroll.ScrollToCellWithinTime(scrollIndex, scrollTime, scrollOffset, scrollMode); + } + EditorGUILayout.EndHorizontal(); + #endregion + } + } +} \ No newline at end of file diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/LoopScrollRectInspector.cs.meta b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/LoopScrollRectInspector.cs.meta new file mode 100644 index 0000000..4754ff3 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/LoopScrollRectInspector.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 216d44a40b90b944db6c5f4624768e58 +timeCreated: 1439395663 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/SGDefaultControls.cs b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/SGDefaultControls.cs new file mode 100644 index 0000000..de6413a --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/SGDefaultControls.cs @@ -0,0 +1,182 @@ +using UnityEngine; +using System.Collections.Generic; + +namespace UnityEngine.UI +{ + public static class SGDefaultControls + { + #region code from DefaultControls.cs + public struct Resources + { + public Sprite standard; + public Sprite background; + public Sprite inputField; + public Sprite knob; + public Sprite checkmark; + public Sprite dropdown; + public Sprite mask; + } + + private const float kWidth = 160f; + private const float kThickHeight = 30f; + private const float kThinHeight = 20f; + //private static Vector2 s_ThickElementSize = new Vector2(kWidth, kThickHeight); + //private static Vector2 s_ThinElementSize = new Vector2(kWidth, kThinHeight); + //private static Vector2 s_ImageElementSize = new Vector2(100f, 100f); + //private static Color s_DefaultSelectableColor = new Color(1f, 1f, 1f, 1f); + //private static Color s_PanelColor = new Color(1f, 1f, 1f, 0.392f); + private static Color s_TextColor = new Color(50f / 255f, 50f / 255f, 50f / 255f, 1f); + + // Helper methods at top + + private static GameObject CreateUIElementRoot(string name, Vector2 size) + { + GameObject child = new GameObject(name); + RectTransform rectTransform = child.AddComponent(); + rectTransform.sizeDelta = size; + return child; + } + + static GameObject CreateUIObject(string name, GameObject parent) + { + GameObject go = new GameObject(name); + go.AddComponent(); + SetParentAndAlign(go, parent); + return go; + } + + private static void SetDefaultTextValues(Text lbl) + { + // Set text values we want across UI elements in default controls. + // Don't set values which are the same as the default values for the Text component, + // since there's no point in that, and it's good to keep them as consistent as possible. + lbl.color = s_TextColor; + } + + private static void SetDefaultColorTransitionValues(Selectable slider) + { + ColorBlock colors = slider.colors; + colors.highlightedColor = new Color(0.882f, 0.882f, 0.882f); + colors.pressedColor = new Color(0.698f, 0.698f, 0.698f); + colors.disabledColor = new Color(0.521f, 0.521f, 0.521f); + } + + private static void SetParentAndAlign(GameObject child, GameObject parent) + { + if (parent == null) + return; + + child.transform.SetParent(parent.transform, false); + SetLayerRecursively(child, parent.layer); + } + + private static void SetLayerRecursively(GameObject go, int layer) + { + go.layer = layer; + Transform t = go.transform; + for (int i = 0; i < t.childCount; i++) + SetLayerRecursively(t.GetChild(i).gameObject, layer); + } + #endregion + + public static GameObject CreateLoopHorizontalScrollRect(DefaultControls.Resources resources) + { + GameObject root = CreateUIElementRoot("Loop Horizontal Scroll Rect", new Vector2(200, 200)); + + GameObject viewport = CreateUIObject("Viewport", root); + + RectTransform viewportRT = viewport.GetComponent(); + viewportRT.anchorMin = new Vector2(0, 0); + viewportRT.anchorMax = new Vector2(1, 1); + viewportRT.sizeDelta = new Vector2(0, 0); + viewportRT.pivot = new Vector2(0.5f, 0.5f); + + viewport.AddComponent(); + + GameObject content = CreateUIObject("Content", viewport); + + RectTransform contentRT = content.GetComponent(); + contentRT.anchorMin = new Vector2(0, 0); + contentRT.anchorMax = new Vector2(0, 1); + contentRT.sizeDelta = new Vector2(0, 0); + contentRT.pivot = new Vector2(0, 0.5f); + + // Setup UI components. + + LoopHorizontalScrollRect scrollRect = root.AddComponent(); + scrollRect.content = contentRT; + scrollRect.viewport = viewportRT; + scrollRect.horizontalScrollbar = null; + scrollRect.verticalScrollbar = null; + scrollRect.horizontal = true; + scrollRect.vertical = false; + scrollRect.horizontalScrollbarVisibility = LoopScrollRect.ScrollbarVisibility.Permanent; + scrollRect.verticalScrollbarVisibility = LoopScrollRect.ScrollbarVisibility.Permanent; + scrollRect.horizontalScrollbarSpacing = 0; + scrollRect.verticalScrollbarSpacing = 0; + + root.AddComponent(); + + HorizontalLayoutGroup layoutGroup = content.AddComponent(); + layoutGroup.childAlignment = TextAnchor.MiddleLeft; + layoutGroup.childForceExpandWidth = false; + layoutGroup.childForceExpandHeight = true; + + ContentSizeFitter sizeFitter = content.AddComponent(); + sizeFitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize; + sizeFitter.verticalFit = ContentSizeFitter.FitMode.Unconstrained; + + return root; + } + + public static GameObject CreateLoopVerticalScrollRect(DefaultControls.Resources resources) + { + GameObject root = CreateUIElementRoot("Loop Vertical Scroll Rect", new Vector2(200, 200)); + + GameObject viewport = CreateUIObject("Viewport", root); + + RectTransform viewportRT = viewport.GetComponent(); + viewportRT.anchorMin = new Vector2(0, 0); + viewportRT.anchorMax = new Vector2(1, 1); + viewportRT.sizeDelta = new Vector2(0, 0); + viewportRT.pivot = new Vector2(0.5f, 0.5f); + + viewport.AddComponent(); + + GameObject content = CreateUIObject("Content", viewport); + + RectTransform contentRT = content.GetComponent(); + contentRT.anchorMin = new Vector2(0, 1); + contentRT.anchorMax = new Vector2(1, 1); + contentRT.sizeDelta = new Vector2(0, 0); + contentRT.pivot = new Vector2(0.5f, 1); + + // Setup UI components. + + LoopVerticalScrollRect scrollRect = root.AddComponent(); + scrollRect.content = contentRT; + scrollRect.viewport = viewportRT; + scrollRect.horizontalScrollbar = null; + scrollRect.verticalScrollbar = null; + scrollRect.horizontal = false; + scrollRect.vertical = true; + scrollRect.horizontalScrollbarVisibility = LoopScrollRect.ScrollbarVisibility.Permanent; + scrollRect.verticalScrollbarVisibility = LoopScrollRect.ScrollbarVisibility.Permanent; + scrollRect.horizontalScrollbarSpacing = 0; + scrollRect.verticalScrollbarSpacing = 0; + + root.AddComponent(); + + VerticalLayoutGroup layoutGroup = content.AddComponent(); + layoutGroup.childAlignment = TextAnchor.UpperCenter; + layoutGroup.childForceExpandWidth = true; + layoutGroup.childForceExpandHeight = false; + + ContentSizeFitter sizeFitter = content.AddComponent(); + sizeFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained; + sizeFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; + + return root; + } + } +} diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/SGDefaultControls.cs.meta b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/SGDefaultControls.cs.meta new file mode 100644 index 0000000..882367d --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/SGDefaultControls.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9e2cfa47387224a4eb069fc6dc8ac8b3 +timeCreated: 1476279563 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/SGMenuOptions.cs b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/SGMenuOptions.cs new file mode 100644 index 0000000..650fcd8 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/SGMenuOptions.cs @@ -0,0 +1,151 @@ +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace UnityEditor.UI +{ + static internal class SGMenuOptions + { + #region code from MenuOptions.cs + private const string kUILayerName = "UI"; + + private const string kStandardSpritePath = "UI/Skin/UISprite.psd"; + private const string kBackgroundSpritePath = "UI/Skin/Background.psd"; + private const string kInputFieldBackgroundPath = "UI/Skin/InputFieldBackground.psd"; + private const string kKnobPath = "UI/Skin/Knob.psd"; + private const string kCheckmarkPath = "UI/Skin/Checkmark.psd"; + private const string kDropdownArrowPath = "UI/Skin/DropdownArrow.psd"; + private const string kMaskPath = "UI/Skin/UIMask.psd"; + + static private DefaultControls.Resources s_StandardResources; + + static private DefaultControls.Resources GetStandardResources() + { + if (s_StandardResources.standard == null) + { + s_StandardResources.standard = AssetDatabase.GetBuiltinExtraResource(kStandardSpritePath); + s_StandardResources.background = AssetDatabase.GetBuiltinExtraResource(kBackgroundSpritePath); + s_StandardResources.inputField = AssetDatabase.GetBuiltinExtraResource(kInputFieldBackgroundPath); + s_StandardResources.knob = AssetDatabase.GetBuiltinExtraResource(kKnobPath); + s_StandardResources.checkmark = AssetDatabase.GetBuiltinExtraResource(kCheckmarkPath); + s_StandardResources.dropdown = AssetDatabase.GetBuiltinExtraResource(kDropdownArrowPath); + s_StandardResources.mask = AssetDatabase.GetBuiltinExtraResource(kMaskPath); + } + return s_StandardResources; + } + + private static void SetPositionVisibleinSceneView(RectTransform canvasRTransform, RectTransform itemTransform) + { + // Find the best scene view + SceneView sceneView = SceneView.lastActiveSceneView; + if (sceneView == null && SceneView.sceneViews.Count > 0) + sceneView = SceneView.sceneViews[0] as SceneView; + + // Couldn't find a SceneView. Don't set position. + if (sceneView == null || sceneView.camera == null) + return; + + // Create world space Plane from canvas position. + Vector2 localPlanePosition; + Camera camera = sceneView.camera; + Vector3 position = Vector3.zero; + if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRTransform, new Vector2(camera.pixelWidth / 2, camera.pixelHeight / 2), camera, out localPlanePosition)) + { + // Adjust for canvas pivot + localPlanePosition.x = localPlanePosition.x + canvasRTransform.sizeDelta.x * canvasRTransform.pivot.x; + localPlanePosition.y = localPlanePosition.y + canvasRTransform.sizeDelta.y * canvasRTransform.pivot.y; + + localPlanePosition.x = Mathf.Clamp(localPlanePosition.x, 0, canvasRTransform.sizeDelta.x); + localPlanePosition.y = Mathf.Clamp(localPlanePosition.y, 0, canvasRTransform.sizeDelta.y); + + // Adjust for anchoring + position.x = localPlanePosition.x - canvasRTransform.sizeDelta.x * itemTransform.anchorMin.x; + position.y = localPlanePosition.y - canvasRTransform.sizeDelta.y * itemTransform.anchorMin.y; + + Vector3 minLocalPosition; + minLocalPosition.x = canvasRTransform.sizeDelta.x * (0 - canvasRTransform.pivot.x) + itemTransform.sizeDelta.x * itemTransform.pivot.x; + minLocalPosition.y = canvasRTransform.sizeDelta.y * (0 - canvasRTransform.pivot.y) + itemTransform.sizeDelta.y * itemTransform.pivot.y; + + Vector3 maxLocalPosition; + maxLocalPosition.x = canvasRTransform.sizeDelta.x * (1 - canvasRTransform.pivot.x) - itemTransform.sizeDelta.x * itemTransform.pivot.x; + maxLocalPosition.y = canvasRTransform.sizeDelta.y * (1 - canvasRTransform.pivot.y) - itemTransform.sizeDelta.y * itemTransform.pivot.y; + + position.x = Mathf.Clamp(position.x, minLocalPosition.x, maxLocalPosition.x); + position.y = Mathf.Clamp(position.y, minLocalPosition.y, maxLocalPosition.y); + } + + itemTransform.anchoredPosition = position; + itemTransform.localRotation = Quaternion.identity; + itemTransform.localScale = Vector3.one; + } + + private static void PlaceUIElementRoot(GameObject element, MenuCommand menuCommand) + { + GameObject parent = menuCommand.context as GameObject; + if (parent == null || parent.GetComponentInParent() == null) + { + parent = GetOrCreateCanvasGameObject(); + } + + string uniqueName = GameObjectUtility.GetUniqueNameForSibling(parent.transform, element.name); + element.name = uniqueName; + Undo.RegisterCreatedObjectUndo(element, "Create " + element.name); + Undo.SetTransformParent(element.transform, parent.transform, "Parent " + element.name); + GameObjectUtility.SetParentAndAlign(element, parent); + if (parent != menuCommand.context) // not a context click, so center in sceneview + SetPositionVisibleinSceneView(parent.GetComponent(), element.GetComponent()); + + Selection.activeGameObject = element; + } + + static public GameObject CreateNewUI() + { + // Root for the UI + var root = new GameObject("Canvas"); + root.layer = LayerMask.NameToLayer(kUILayerName); + Canvas canvas = root.AddComponent(); + canvas.renderMode = RenderMode.ScreenSpaceOverlay; + root.AddComponent(); + root.AddComponent(); + Undo.RegisterCreatedObjectUndo(root, "Create " + root.name); + + // if there is no event system add one... + // CreateEventSystem(false); + return root; + } + + // Helper function that returns a Canvas GameObject; preferably a parent of the selection, or other existing Canvas. + static public GameObject GetOrCreateCanvasGameObject() + { + GameObject selectedGo = Selection.activeGameObject; + + // Try to find a gameobject that is the selected GO or one if its parents. + Canvas canvas = (selectedGo != null) ? selectedGo.GetComponentInParent() : null; + if (canvas != null && canvas.gameObject.activeInHierarchy) + return canvas.gameObject; + + // No canvas in selection or its parents? Then use just any canvas.. + canvas = Object.FindObjectOfType(typeof(Canvas)) as Canvas; + if (canvas != null && canvas.gameObject.activeInHierarchy) + return canvas.gameObject; + + // No canvas in the scene at all? Then create a new one. + return SGMenuOptions.CreateNewUI(); + } + #endregion + + [MenuItem("GameObject/UI/Loop Horizontal Scroll Rect", false, 2151)] + static public void AddLoopHorizontalScrollRect(MenuCommand menuCommand) + { + GameObject go = SGDefaultControls.CreateLoopHorizontalScrollRect(GetStandardResources()); + PlaceUIElementRoot(go, menuCommand); + } + + [MenuItem("GameObject/UI/Loop Vertical Scroll Rect", false, 2152)] + static public void AddLoopVerticalScrollRect(MenuCommand menuCommand) + { + GameObject go = SGDefaultControls.CreateLoopVerticalScrollRect(GetStandardResources()); + PlaceUIElementRoot(go, menuCommand); + } + } +} \ No newline at end of file diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/SGMenuOptions.cs.meta b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/SGMenuOptions.cs.meta new file mode 100644 index 0000000..b1d1b58 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Editor/SGMenuOptions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c4b63bf28f5af0e42a464ac316fef603 +timeCreated: 1476279563 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime.meta b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime.meta new file mode 100644 index 0000000..f6f0ee2 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ec0ddcd49b026ab4fb6b7d49fd693e57 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopHorizontalScrollRect.cs b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopHorizontalScrollRect.cs new file mode 100644 index 0000000..2aa58fa --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopHorizontalScrollRect.cs @@ -0,0 +1,188 @@ +using UnityEngine; +using System.Collections; + +namespace UnityEngine.UI +{ + [AddComponentMenu("UI/Loop Horizontal Scroll Rect", 50)] + [DisallowMultipleComponent] + public class LoopHorizontalScrollRect : LoopScrollRect + { + protected LoopHorizontalScrollRect() + { + direction = LoopScrollRectDirection.Horizontal; + } + + protected override float GetSize(RectTransform item, bool includeSpacing) + { + float size = includeSpacing ? contentSpacing : 0; + if (m_GridLayout != null) + { + size += m_GridLayout.cellSize.x; + } + else + { + size += LoopScrollSizeUtils.GetPreferredWidth(item); + } + size *= m_Content.localScale.x; + return size; + } + + protected override float GetDimension(Vector2 vector) + { + return -vector.x; + } + + protected override float GetAbsDimension(Vector2 vector) + { + return vector.x; + } + + protected override Vector2 GetVector(float value) + { + return new Vector2(-value, 0); + } + + protected override void Awake() + { + base.Awake(); + if (m_Content) + { + GridLayoutGroup layout = m_Content.GetComponent(); + if (layout != null && layout.constraint != GridLayoutGroup.Constraint.FixedRowCount) + { + Debug.LogError("[LoopScrollRect] unsupported GridLayoutGroup constraint"); + } + } + } + + protected override bool UpdateItems(ref Bounds viewBounds, ref Bounds contentBounds) + { + bool changed = false; + + // special case: handling move several page in one frame + if ((viewBounds.size.x < contentBounds.min.x - viewBounds.max.x) && itemTypeEnd > itemTypeStart) + { + float currentSize = contentBounds.size.x; + float elementSize = EstimiateElementSize(); + ReturnToTempPool(false, itemTypeEnd - itemTypeStart); + itemTypeEnd = itemTypeStart; + + int offsetCount = Mathf.FloorToInt((contentBounds.min.x - viewBounds.max.x) / (elementSize + contentSpacing)); + if (totalCount >= 0 && itemTypeStart - offsetCount * contentConstraintCount < 0) + { + offsetCount = Mathf.FloorToInt((float)(itemTypeStart) / contentConstraintCount); + } + itemTypeStart -= offsetCount * contentConstraintCount; + if (totalCount >= 0) + { + itemTypeStart = Mathf.Max(itemTypeStart, 0); + } + itemTypeEnd = itemTypeStart; + itemTypeSize = 0; + + float offset = offsetCount * (elementSize + contentSpacing); + m_Content.anchoredPosition -= new Vector2(offset + (reverseDirection ? currentSize : 0), 0); + contentBounds.center -= new Vector3(offset + currentSize / 2, 0, 0); + contentBounds.size = Vector3.zero; + + changed = true; + } + + if ((viewBounds.min.x - contentBounds.max.x > viewBounds.size.x) && itemTypeEnd > itemTypeStart) + { + int maxItemTypeStart = -1; + if (totalCount >= 0) + { + maxItemTypeStart = Mathf.Max(0, totalCount - (itemTypeEnd - itemTypeStart)); + maxItemTypeStart = (maxItemTypeStart / contentConstraintCount) * contentConstraintCount; + } + float currentSize = contentBounds.size.x; + float elementSize = EstimiateElementSize(); + ReturnToTempPool(true, itemTypeEnd - itemTypeStart); + // TODO: fix with contentConstraint? + itemTypeStart = itemTypeEnd; + + int offsetCount = Mathf.FloorToInt((viewBounds.min.x - contentBounds.max.x) / (elementSize + contentSpacing)); + if (maxItemTypeStart >= 0 && itemTypeStart + offsetCount * contentConstraintCount > maxItemTypeStart) + { + offsetCount = Mathf.FloorToInt((float)(maxItemTypeStart - itemTypeStart) / contentConstraintCount); + } + itemTypeStart += offsetCount * contentConstraintCount; + if (totalCount >= 0) + { + itemTypeStart = Mathf.Max(itemTypeStart, 0); + } + itemTypeEnd = itemTypeStart; + itemTypeSize = 0; + + float offset = offsetCount * (elementSize + contentSpacing); + m_Content.anchoredPosition += new Vector2(offset + (reverseDirection ? 0 : currentSize), 0); + contentBounds.center += new Vector3(offset + currentSize / 2, 0, 0); + contentBounds.size = Vector3.zero; + + changed = true; + } + + if (viewBounds.max.x > contentBounds.max.x - m_ContentRightPadding) + { + float size = NewItemAtEnd(), totalSize = size; + while (size > 0 && viewBounds.max.x > contentBounds.max.x - m_ContentRightPadding + totalSize) + { + size = NewItemAtEnd(); + totalSize += size; + } + if (totalSize > 0) + changed = true; + } + else if ((itemTypeEnd % contentConstraintCount != 0) && (itemTypeEnd < totalCount || totalCount < 0)) + { + NewItemAtEnd(); + } + + if (viewBounds.min.x < contentBounds.min.x + m_ContentLeftPadding) + { + float size = NewItemAtStart(), totalSize = size; + while (size > 0 && viewBounds.min.x < contentBounds.min.x + m_ContentLeftPadding - totalSize) + { + size = NewItemAtStart(); + totalSize += size; + } + if (totalSize > 0) + changed = true; + } + + if (viewBounds.max.x < contentBounds.max.x - threshold - m_ContentRightPadding + && viewBounds.size.x < contentBounds.size.x - threshold) + { + float size = DeleteItemAtEnd(), totalSize = size; + while (size > 0 && viewBounds.max.x < contentBounds.max.x - threshold - m_ContentRightPadding - totalSize) + { + size = DeleteItemAtEnd(); + totalSize += size; + } + if (totalSize > 0) + changed = true; + } + + if (viewBounds.min.x > contentBounds.min.x + threshold + m_ContentLeftPadding + && viewBounds.size.x < contentBounds.size.x - threshold) + { + float size = DeleteItemAtStart(), totalSize = size; + while (size > 0 && viewBounds.min.x > contentBounds.min.x + threshold + m_ContentLeftPadding + totalSize) + { + size = DeleteItemAtStart(); + totalSize += size; + } + if (totalSize > 0) + changed = true; + } + + if (changed) + { + ClearTempPool(); + } + + return changed; + } + } +} \ No newline at end of file diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopHorizontalScrollRect.cs.meta b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopHorizontalScrollRect.cs.meta new file mode 100644 index 0000000..6ff936a --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopHorizontalScrollRect.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ab7b38d60c9f6a944831d24146f39793 +timeCreated: 1439395663 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopHorizontalScrollRectMulti.cs b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopHorizontalScrollRectMulti.cs new file mode 100644 index 0000000..5286235 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopHorizontalScrollRectMulti.cs @@ -0,0 +1,188 @@ +using UnityEngine; +using System.Collections; + +namespace UnityEngine.UI +{ + [AddComponentMenu("UI/Loop Horizontal Scroll Rect(MultiPrefab)", 52)] + [DisallowMultipleComponent] + public class LoopHorizontalScrollRectMulti : LoopScrollRectMulti + { + protected LoopHorizontalScrollRectMulti() + { + direction = LoopScrollRectDirection.Horizontal; + } + + protected override float GetSize(RectTransform item, bool includeSpacing) + { + float size = includeSpacing ? contentSpacing : 0; + if (m_GridLayout != null) + { + size += m_GridLayout.cellSize.x; + } + else + { + size += LoopScrollSizeUtils.GetPreferredWidth(item); + } + size *= m_Content.localScale.x; + return size; + } + + protected override float GetDimension(Vector2 vector) + { + return -vector.x; + } + + protected override float GetAbsDimension(Vector2 vector) + { + return vector.x; + } + + protected override Vector2 GetVector(float value) + { + return new Vector2(-value, 0); + } + + protected override void Awake() + { + base.Awake(); + if (m_Content) + { + GridLayoutGroup layout = m_Content.GetComponent(); + if (layout != null && layout.constraint != GridLayoutGroup.Constraint.FixedRowCount) + { + Debug.LogError("[LoopScrollRect] unsupported GridLayoutGroup constraint"); + } + } + } + + protected override bool UpdateItems(ref Bounds viewBounds, ref Bounds contentBounds) + { + bool changed = false; + + // special case: handling move several page in one frame + if ((viewBounds.size.x < contentBounds.min.x - viewBounds.max.x) && itemTypeEnd > itemTypeStart) + { + float currentSize = contentBounds.size.x; + float elementSize = EstimiateElementSize(); + ReturnToTempPool(false, itemTypeEnd - itemTypeStart); + itemTypeEnd = itemTypeStart; + + int offsetCount = Mathf.FloorToInt((contentBounds.min.x - viewBounds.max.x) / (elementSize + contentSpacing)); + if (totalCount >= 0 && itemTypeStart - offsetCount * contentConstraintCount < 0) + { + offsetCount = Mathf.FloorToInt((float)(itemTypeStart) / contentConstraintCount); + } + itemTypeStart -= offsetCount * contentConstraintCount; + if (totalCount >= 0) + { + itemTypeStart = Mathf.Max(itemTypeStart, 0); + } + itemTypeEnd = itemTypeStart; + itemTypeSize = 0; + + float offset = offsetCount * (elementSize + contentSpacing); + m_Content.anchoredPosition -= new Vector2(offset + (reverseDirection ? currentSize : 0), 0); + contentBounds.center -= new Vector3(offset + currentSize / 2, 0, 0); + contentBounds.size = Vector3.zero; + + changed = true; + } + + if ((viewBounds.min.x - contentBounds.max.x > viewBounds.size.x) && itemTypeEnd > itemTypeStart) + { + int maxItemTypeStart = -1; + if (totalCount >= 0) + { + maxItemTypeStart = Mathf.Max(0, totalCount - (itemTypeEnd - itemTypeStart)); + maxItemTypeStart = (maxItemTypeStart / contentConstraintCount) * contentConstraintCount; + } + float currentSize = contentBounds.size.x; + float elementSize = EstimiateElementSize(); + ReturnToTempPool(true, itemTypeEnd - itemTypeStart); + // TODO: fix with contentConstraint? + itemTypeStart = itemTypeEnd; + + int offsetCount = Mathf.FloorToInt((viewBounds.min.x - contentBounds.max.x) / (elementSize + contentSpacing)); + if (maxItemTypeStart >= 0 && itemTypeStart + offsetCount * contentConstraintCount > maxItemTypeStart) + { + offsetCount = Mathf.FloorToInt((float)(maxItemTypeStart - itemTypeStart) / contentConstraintCount); + } + itemTypeStart += offsetCount * contentConstraintCount; + if (totalCount >= 0) + { + itemTypeStart = Mathf.Max(itemTypeStart, 0); + } + itemTypeEnd = itemTypeStart; + itemTypeSize = 0; + + float offset = offsetCount * (elementSize + contentSpacing); + m_Content.anchoredPosition += new Vector2(offset + (reverseDirection ? 0 : currentSize), 0); + contentBounds.center += new Vector3(offset + currentSize / 2, 0, 0); + contentBounds.size = Vector3.zero; + + changed = true; + } + + if (viewBounds.max.x > contentBounds.max.x - m_ContentRightPadding) + { + float size = NewItemAtEnd(), totalSize = size; + while (size > 0 && viewBounds.max.x > contentBounds.max.x - m_ContentRightPadding + totalSize) + { + size = NewItemAtEnd(); + totalSize += size; + } + if (totalSize > 0) + changed = true; + } + else if ((itemTypeEnd % contentConstraintCount != 0) && (itemTypeEnd < totalCount || totalCount < 0)) + { + NewItemAtEnd(); + } + + if (viewBounds.min.x < contentBounds.min.x + m_ContentLeftPadding) + { + float size = NewItemAtStart(), totalSize = size; + while (size > 0 && viewBounds.min.x < contentBounds.min.x + m_ContentLeftPadding - totalSize) + { + size = NewItemAtStart(); + totalSize += size; + } + if (totalSize > 0) + changed = true; + } + + if (viewBounds.max.x < contentBounds.max.x - threshold - m_ContentRightPadding + && viewBounds.size.x < contentBounds.size.x - threshold) + { + float size = DeleteItemAtEnd(), totalSize = size; + while (size > 0 && viewBounds.max.x < contentBounds.max.x - threshold - m_ContentRightPadding - totalSize) + { + size = DeleteItemAtEnd(); + totalSize += size; + } + if (totalSize > 0) + changed = true; + } + + if (viewBounds.min.x > contentBounds.min.x + threshold + m_ContentLeftPadding + && viewBounds.size.x < contentBounds.size.x - threshold) + { + float size = DeleteItemAtStart(), totalSize = size; + while (size > 0 && viewBounds.min.x > contentBounds.min.x + threshold + m_ContentLeftPadding + totalSize) + { + size = DeleteItemAtStart(); + totalSize += size; + } + if (totalSize > 0) + changed = true; + } + + if (changed) + { + ClearTempPool(); + } + + return changed; + } + } +} \ No newline at end of file diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopHorizontalScrollRectMulti.cs.meta b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopHorizontalScrollRectMulti.cs.meta new file mode 100644 index 0000000..c169b7d --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopHorizontalScrollRectMulti.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0aa64ab4e86f574469b5d4fda2e9c85f +timeCreated: 1439395663 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollDataSource.cs b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollDataSource.cs new file mode 100644 index 0000000..7cd6577 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollDataSource.cs @@ -0,0 +1,10 @@ +using UnityEngine; +using System.Collections; + +namespace UnityEngine.UI +{ + public interface LoopScrollDataSource + { + void ProvideData(Transform transform, int idx); + } +} \ No newline at end of file diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollDataSource.cs.meta b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollDataSource.cs.meta new file mode 100644 index 0000000..f668265 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollDataSource.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: be1ddd0ddf17846f0b38566071ee623e +timeCreated: 1500356133 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollMultiDataSource.cs b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollMultiDataSource.cs new file mode 100644 index 0000000..7180f96 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollMultiDataSource.cs @@ -0,0 +1,10 @@ +using UnityEngine; +using System.Collections; + +namespace UnityEngine.UI +{ + public interface LoopScrollMultiDataSource + { + void ProvideData(Transform transform, int index); + } +} \ No newline at end of file diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollMultiDataSource.cs.meta b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollMultiDataSource.cs.meta new file mode 100644 index 0000000..ea2aa95 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollMultiDataSource.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8730c6d35f93cb946b80539f595b48c1 +timeCreated: 1500356133 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollPrefabSource.cs b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollPrefabSource.cs new file mode 100644 index 0000000..e27ef64 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollPrefabSource.cs @@ -0,0 +1,12 @@ +using UnityEngine; +using System.Collections; + +namespace UnityEngine.UI +{ + public interface LoopScrollPrefabSource + { + GameObject GetObject(int index); + + void ReturnObject(Transform trans); + } +} diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollPrefabSource.cs.meta b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollPrefabSource.cs.meta new file mode 100644 index 0000000..c46426d --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollPrefabSource.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4cea3807a046c4500be20219e5c46432 +timeCreated: 1500356133 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRect.cs b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRect.cs new file mode 100644 index 0000000..249a251 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRect.cs @@ -0,0 +1,76 @@ +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.EventSystems; +using System; +using System.Collections; +using System.Collections.Generic; + +namespace UnityEngine.UI +{ + public abstract class LoopScrollRect : LoopScrollRectBase + { + [HideInInspector] + [NonSerialized] + public LoopScrollDataSource dataSource = null; + + protected override void ProvideData(Transform transform, int index) + { + dataSource.ProvideData(transform, index); + } + + protected override RectTransform GetFromTempPool(int itemIdx) + { + RectTransform nextItem = null; + if (deletedItemTypeStart > 0) + { + deletedItemTypeStart--; + nextItem = m_Content.GetChild(0) as RectTransform; + nextItem.SetSiblingIndex(itemIdx - itemTypeStart + deletedItemTypeStart); + } + else if (deletedItemTypeEnd > 0) + { + deletedItemTypeEnd--; + nextItem = m_Content.GetChild(m_Content.childCount - 1) as RectTransform; + nextItem.SetSiblingIndex(itemIdx - itemTypeStart + deletedItemTypeStart); + } + else + { + nextItem = prefabSource.GetObject(itemIdx).transform as RectTransform; + nextItem.transform.SetParent(m_Content, false); + nextItem.gameObject.SetActive(true); + } + ProvideData(nextItem, itemIdx); + return nextItem; + } + + protected override void ReturnToTempPool(bool fromStart, int count) + { + if (fromStart) + deletedItemTypeStart += count; + else + deletedItemTypeEnd += count; + } + + protected override void ClearTempPool() + { + Debug.Assert(m_Content.childCount >= deletedItemTypeStart + deletedItemTypeEnd); + if (deletedItemTypeStart > 0) + { + for (int i = deletedItemTypeStart - 1; i >= 0; i--) + { + prefabSource.ReturnObject(m_Content.GetChild(i)); + } + deletedItemTypeStart = 0; + } + if (deletedItemTypeEnd > 0) + { + int t = m_Content.childCount - deletedItemTypeEnd; + for (int i = m_Content.childCount - 1; i >= t; i--) + { + prefabSource.ReturnObject(m_Content.GetChild(i)); + } + deletedItemTypeEnd = 0; + } + } + } +} \ No newline at end of file diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRect.cs.meta b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRect.cs.meta new file mode 100644 index 0000000..89e8f60 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRect.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4ec983a492fb0204bacc07738659994f +timeCreated: 1439395663 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRectBase.cs b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRectBase.cs new file mode 100644 index 0000000..6c33e2a --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRectBase.cs @@ -0,0 +1,2401 @@ +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.EventSystems; +using System; +using System.Collections; +using System.Collections.Generic; + +namespace UnityEngine.UI +{ + [AddComponentMenu("")] + [DisallowMultipleComponent] + [RequireComponent(typeof(RectTransform))] + /// + /// A component for making a child RectTransform scroll with reuseable content. + /// + /// + /// LoopScrollRect will not do any clipping on its own. Combined with a Mask component, it can be turned into a loop scroll view. + /// + public abstract class LoopScrollRectBase : UIBehaviour, IInitializePotentialDragHandler, IBeginDragHandler, IEndDragHandler, IDragHandler, IScrollHandler, ICanvasElement, ILayoutElement, ILayoutGroup + { + //==========LoopScrollRect========== + /// + /// The scroll data source to fill items. + /// + [HideInInspector] + [NonSerialized] + public LoopScrollPrefabSource prefabSource = null; + + /// + /// The scroll's total count for items with id in [0, totalCount]. Negative value like -1 means infinite items. + /// + [Tooltip("Total count, negative means INFINITE mode")] + public int totalCount; + + /// + /// [Optional] Helper for accurate size so we can achieve better scrolling. + /// + [HideInInspector] + [NonSerialized] + public LoopScrollSizeHelper sizeHelper = null; + + /// + /// When threshold reached, we prepare new items outside view. This will be expanded to at least 1.5 * itemSize. + /// + protected float threshold = 0; + + /// + /// Whether we use down-upsize or right-left direction? + /// + [Tooltip("Reverse direction for dragging")] + public bool reverseDirection = false; + + /// + /// The first item id in LoopScroll. + /// + protected int itemTypeStart = 0; + + /// + /// The last item id in LoopScroll. + /// + protected int itemTypeEnd = 0; + + protected float itemTypeSize = 0; + + protected abstract float GetSize(RectTransform item, bool includeSpacing = true); + protected abstract float GetDimension(Vector2 vector); + protected abstract float GetAbsDimension(Vector2 vector); + protected abstract Vector2 GetVector(float value); + /// + /// Direction for LoopScroll. This is a bit confusing with m_Horizontal/m_Vertical. + /// + protected enum LoopScrollRectDirection + { + Vertical, + Horizontal, + } + protected LoopScrollRectDirection direction = LoopScrollRectDirection.Horizontal; + + private bool m_ContentSpaceInit = false; + private float m_ContentSpacing = 0; + protected float m_ContentLeftPadding = 0; + protected float m_ContentRightPadding = 0; + protected float m_ContentTopPadding = 0; + protected float m_ContentBottomPadding = 0; + protected GridLayoutGroup m_GridLayout = null; + protected float contentSpacing + { + get + { + if (m_ContentSpaceInit) + { + return m_ContentSpacing; + } + m_ContentSpaceInit = true; + m_ContentSpacing = 0; + if (m_Content != null) + { + HorizontalOrVerticalLayoutGroup layout1 = m_Content.GetComponent(); + if (layout1 != null) + { + m_ContentSpacing = layout1.spacing; + m_ContentLeftPadding = layout1.padding.left; + m_ContentRightPadding = layout1.padding.right; + m_ContentTopPadding = layout1.padding.top; + m_ContentBottomPadding = layout1.padding.bottom; + } + m_GridLayout = m_Content.GetComponent(); + if (m_GridLayout != null) + { + m_ContentSpacing = GetAbsDimension(m_GridLayout.spacing); + m_ContentLeftPadding = m_GridLayout.padding.left; + m_ContentRightPadding = m_GridLayout.padding.right; + m_ContentTopPadding = m_GridLayout.padding.top; + m_ContentBottomPadding = m_GridLayout.padding.bottom; + } + } + return m_ContentSpacing; + } + } + + private bool m_ContentConstraintCountInit = false; + private int m_ContentConstraintCount = 0; + protected int contentConstraintCount + { + get + { + if (m_ContentConstraintCountInit) + { + return m_ContentConstraintCount; + } + m_ContentConstraintCountInit = true; + m_ContentConstraintCount = 1; + if (m_Content != null) + { + GridLayoutGroup layout2 = m_Content.GetComponent(); + if (layout2 != null) + { + if (layout2.constraint == GridLayoutGroup.Constraint.Flexible) + { + Debug.LogWarning("[LoopScrollRect] Flexible not supported yet"); + } + m_ContentConstraintCount = layout2.constraintCount; + } + } + return m_ContentConstraintCount; + } + } + + /// + /// The first line in scroll. Grid may have multiply items in one line. + /// + protected int StartLine + { + get + { + return Mathf.CeilToInt((float)(itemTypeStart) / contentConstraintCount); + } + } + + /// + /// Current line count in scroll. Grid may have multiply items in one line. + /// + protected int CurrentLines + { + get + { + return Mathf.CeilToInt((float)(itemTypeEnd - itemTypeStart) / contentConstraintCount); + } + } + + /// + /// Total line count in scroll. Grid may have multiply items in one line. + /// + protected int TotalLines + { + get + { + return Mathf.CeilToInt((float)(totalCount) / contentConstraintCount); + } + } + + protected virtual bool UpdateItems(ref Bounds viewBounds, ref Bounds contentBounds) { return false; } + //==========LoopScrollRect========== + + /// + /// A setting for which behavior to use when content moves beyond the confines of its container. + /// + /// + /// + /// using UnityEngine; + /// using System.Collections; + /// using UnityEngine.UI; // Required when Using UI elements. + /// + /// public class ExampleClass : MonoBehaviour + /// { + /// public ScrollRect myScrollRect; + /// public Scrollbar newScrollBar; + /// + /// //Called when a button is pressed + /// public void Example(int option) + /// { + /// if (option == 0) + /// { + /// myScrollRect.movementType = ScrollRect.MovementType.Clamped; + /// } + /// else if (option == 1) + /// { + /// myScrollRect.movementType = ScrollRect.MovementType.Elastic; + /// } + /// else if (option == 2) + /// { + /// myScrollRect.movementType = ScrollRect.MovementType.Unrestricted; + /// } + /// } + /// } + /// + /// + public enum MovementType + { + /// + /// Unrestricted movement. The content can move forever. + /// + Unrestricted, + + /// + /// Elastic movement. The content is allowed to temporarily move beyond the container, but is pulled back elastically. + /// + Elastic, + + /// + /// Clamped movement. The content can not be moved beyond its container. + /// + Clamped, + } + + /// + /// Enum for which behavior to use for scrollbar visibility. + /// + public enum ScrollbarVisibility + { + /// + /// Always show the scrollbar. + /// + Permanent, + + /// + /// Automatically hide the scrollbar when no scrolling is needed on this axis. The viewport rect will not be changed. + /// + AutoHide, + + /// + /// Automatically hide the scrollbar when no scrolling is needed on this axis, and expand the viewport rect accordingly. + /// + /// + /// When this setting is used, the scrollbar and the viewport rect become driven, meaning that values in the RectTransform are calculated automatically and can't be manually edited. + /// + AutoHideAndExpandViewport, + } + + [Serializable] + /// + /// Event type used by the ScrollRect. + /// + public class ScrollRectEvent : UnityEvent {} + + [SerializeField] + protected RectTransform m_Content; //==========LoopScrollRect========== + + /// + /// The content that can be scrolled. It should be a child of the GameObject with ScrollRect on it. + /// + /// + /// + /// using UnityEngine; + /// using System.Collections; + /// using UnityEngine.UI; // Required when Using UI elements. + /// + /// public class ExampleClass : MonoBehaviour + /// { + /// public ScrollRect myScrollRect; + /// public RectTransform scrollableContent; + /// + /// //Do this when the Save button is selected. + /// public void Start() + /// { + /// // assigns the contect that can be scrolled using the ScrollRect. + /// myScrollRect.content = scrollableContent; + /// } + /// } + /// + /// + public RectTransform content { get { return m_Content; } set { m_Content = value; } } + + [SerializeField] + private bool m_Horizontal = true; + + /// + /// Should horizontal scrolling be enabled? + /// + /// + /// + /// using UnityEngine; + /// using System.Collections; + /// using UnityEngine.UI; // Required when Using UI elements. + /// + /// public class ExampleClass : MonoBehaviour + /// { + /// public ScrollRect myScrollRect; + /// + /// public void Start() + /// { + /// // Is horizontal scrolling enabled? + /// if (myScrollRect.horizontal == true) + /// { + /// Debug.Log("Horizontal Scrolling is Enabled!"); + /// } + /// } + /// } + /// + /// + public bool horizontal { get { return m_Horizontal; } set { m_Horizontal = value; } } + + [SerializeField] + private bool m_Vertical = true; + + /// + /// Should vertical scrolling be enabled? + /// + /// + /// + /// using UnityEngine; + /// using System.Collections; + /// using UnityEngine.UI; // Required when Using UI elements. + /// + /// public class ExampleClass : MonoBehaviour + /// { + /// public ScrollRect myScrollRect; + /// + /// public void Start() + /// { + /// // Is Vertical scrolling enabled? + /// if (myScrollRect.vertical == true) + /// { + /// Debug.Log("Vertical Scrolling is Enabled!"); + /// } + /// } + /// } + /// + /// + public bool vertical { get { return m_Vertical; } set { m_Vertical = value; } } + + [SerializeField] + private MovementType m_MovementType = MovementType.Elastic; + + /// + /// The behavior to use when the content moves beyond the scroll rect. + /// + public MovementType movementType { get { return m_MovementType; } set { m_MovementType = value; } } + + [SerializeField] + private float m_Elasticity = 0.1f; + + /// + /// The amount of elasticity to use when the content moves beyond the scroll rect. + /// + /// + /// + /// using UnityEngine; + /// using System.Collections; + /// using UnityEngine.UI; + /// + /// public class ExampleClass : MonoBehaviour + /// { + /// public ScrollRect myScrollRect; + /// + /// public void Start() + /// { + /// // assigns a new value to the elasticity of the scroll rect. + /// // The higher the number the longer it takes to snap back. + /// myScrollRect.elasticity = 3.0f; + /// } + /// } + /// + /// + public float elasticity { get { return m_Elasticity; } set { m_Elasticity = value; } } + + [SerializeField] + private bool m_Inertia = true; + + /// + /// Should movement inertia be enabled? + /// + /// + /// Inertia means that the scrollrect content will keep scrolling for a while after being dragged. It gradually slows down according to the decelerationRate. + /// + public bool inertia { get { return m_Inertia; } set { m_Inertia = value; } } + + [SerializeField] + private float m_DecelerationRate = 0.135f; // Only used when inertia is enabled + + /// + /// The rate at which movement slows down. + /// + /// + /// The deceleration rate is the speed reduction per second. A value of 0.5 halves the speed each second. The default is 0.135. The deceleration rate is only used when inertia is enabled. + /// + /// + /// + /// using UnityEngine; + /// using System.Collections; + /// using UnityEngine.UI; // Required when Using UI elements. + /// + /// public class ExampleClass : MonoBehaviour + /// { + /// public ScrollRect myScrollRect; + /// + /// public void Start() + /// { + /// // assigns a new value to the decelerationRate of the scroll rect. + /// // The higher the number the longer it takes to decelerate. + /// myScrollRect.decelerationRate = 5.0f; + /// } + /// } + /// + /// + public float decelerationRate { get { return m_DecelerationRate; } set { m_DecelerationRate = value; } } + + [SerializeField] + private float m_ScrollSensitivity = 1.0f; + + /// + /// The sensitivity to scroll wheel and track pad scroll events. + /// + /// + /// Higher values indicate higher sensitivity. + /// + public float scrollSensitivity { get { return m_ScrollSensitivity; } set { m_ScrollSensitivity = value; } } + + [SerializeField] + private RectTransform m_Viewport; + + /// + /// Reference to the viewport RectTransform that is the parent of the content RectTransform. + /// + public RectTransform viewport { get { return m_Viewport; } set { m_Viewport = value; SetDirtyCaching(); } } + + [SerializeField] + private Scrollbar m_HorizontalScrollbar; + + /// + /// Optional Scrollbar object linked to the horizontal scrolling of the ScrollRect. + /// + /// + /// + /// using UnityEngine; + /// using System.Collections; + /// using UnityEngine.UI; // Required when Using UI elements. + /// + /// public class ExampleClass : MonoBehaviour + /// { + /// public ScrollRect myScrollRect; + /// public Scrollbar newScrollBar; + /// + /// public void Start() + /// { + /// // Assigns a scroll bar element to the ScrollRect, allowing you to scroll in the horizontal axis. + /// myScrollRect.horizontalScrollbar = newScrollBar; + /// } + /// } + /// + /// + public Scrollbar horizontalScrollbar + { + get + { + return m_HorizontalScrollbar; + } + set + { + if (m_HorizontalScrollbar) + m_HorizontalScrollbar.onValueChanged.RemoveListener(SetHorizontalNormalizedPosition); + m_HorizontalScrollbar = value; + if (m_HorizontalScrollbar) + m_HorizontalScrollbar.onValueChanged.AddListener(SetHorizontalNormalizedPosition); + SetDirtyCaching(); + } + } + + [SerializeField] + private Scrollbar m_VerticalScrollbar; + + /// + /// Optional Scrollbar object linked to the vertical scrolling of the ScrollRect. + /// + /// + /// + /// using UnityEngine; + /// using System.Collections; + /// using UnityEngine.UI; // Required when Using UI elements. + /// + /// public class ExampleClass : MonoBehaviour + /// { + /// public ScrollRect myScrollRect; + /// public Scrollbar newScrollBar; + /// + /// public void Start() + /// { + /// // Assigns a scroll bar element to the ScrollRect, allowing you to scroll in the vertical axis. + /// myScrollRect.verticalScrollbar = newScrollBar; + /// } + /// } + /// + /// + public Scrollbar verticalScrollbar + { + get + { + return m_VerticalScrollbar; + } + set + { + if (m_VerticalScrollbar) + m_VerticalScrollbar.onValueChanged.RemoveListener(SetVerticalNormalizedPosition); + m_VerticalScrollbar = value; + if (m_VerticalScrollbar) + m_VerticalScrollbar.onValueChanged.AddListener(SetVerticalNormalizedPosition); + SetDirtyCaching(); + } + } + + [SerializeField] + private ScrollbarVisibility m_HorizontalScrollbarVisibility; + + /// + /// The mode of visibility for the horizontal scrollbar. + /// + public ScrollbarVisibility horizontalScrollbarVisibility { get { return m_HorizontalScrollbarVisibility; } set { m_HorizontalScrollbarVisibility = value; SetDirtyCaching(); } } + + [SerializeField] + private ScrollbarVisibility m_VerticalScrollbarVisibility; + + /// + /// The mode of visibility for the vertical scrollbar. + /// + public ScrollbarVisibility verticalScrollbarVisibility { get { return m_VerticalScrollbarVisibility; } set { m_VerticalScrollbarVisibility = value; SetDirtyCaching(); } } + + [SerializeField] + private float m_HorizontalScrollbarSpacing; + + /// + /// The space between the scrollbar and the viewport. + /// + public float horizontalScrollbarSpacing { get { return m_HorizontalScrollbarSpacing; } set { m_HorizontalScrollbarSpacing = value; SetDirty(); } } + + [SerializeField] + private float m_VerticalScrollbarSpacing; + + /// + /// The space between the scrollbar and the viewport. + /// + public float verticalScrollbarSpacing { get { return m_VerticalScrollbarSpacing; } set { m_VerticalScrollbarSpacing = value; SetDirty(); } } + + [SerializeField] + private ScrollRectEvent m_OnValueChanged = new ScrollRectEvent(); + + /// + /// Callback executed when the position of the child changes. + /// + /// + /// onValueChanged is used to watch for changes in the ScrollRect object. + /// The onValueChanged call will use the UnityEvent.AddListener API to watch for + /// changes. When changes happen script code provided by the user will be called. + /// The UnityEvent.AddListener API for UI.ScrollRect._onValueChanged takes a Vector2. + /// + /// Note: The editor allows the onValueChanged value to be set up manually.For example the + /// value can be set to run only a runtime. The object and script function to call are also + /// provided here. + /// + /// The onValueChanged variable can be alternatively set-up at runtime.The script example below + /// shows how this can be done.The script is attached to the ScrollRect object. + /// + /// + /// + /// using UnityEngine; + /// using UnityEngine.UI; + /// + /// public class ExampleScript : MonoBehaviour + /// { + /// static ScrollRect scrollRect; + /// + /// void Start() + /// { + /// scrollRect = GetComponent(); + /// scrollRect.onValueChanged.AddListener(ListenerMethod); + /// } + /// + /// public void ListenerMethod(Vector2 value) + /// { + /// Debug.Log("ListenerMethod: " + value); + /// } + /// } + /// + /// + public ScrollRectEvent onValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = value; } } + + // The offset from handle position to mouse down position + private Vector2 m_PointerStartLocalCursor = Vector2.zero; + protected Vector2 m_ContentStartPosition = Vector2.zero; + + private RectTransform m_ViewRect; + + protected RectTransform viewRect + { + get + { + if (m_ViewRect == null) + m_ViewRect = m_Viewport; + if (m_ViewRect == null) + m_ViewRect = (RectTransform)transform; + return m_ViewRect; + } + } + + protected Bounds m_ContentBounds; + private Bounds m_ViewBounds; + + private Vector2 m_Velocity; + + /// + /// The current velocity of the content. + /// + /// + /// The velocity is defined in units per second. + /// + public Vector2 velocity { get { return m_Velocity; } set { m_Velocity = value; } } + + private bool m_Dragging; + private bool m_Scrolling; + + private Vector2 m_PrevPosition = Vector2.zero; + private Bounds m_PrevContentBounds; + private Bounds m_PrevViewBounds; + [NonSerialized] + private bool m_HasRebuiltLayout = false; + + private bool m_HSliderExpand; + private bool m_VSliderExpand; + private float m_HSliderHeight; + private float m_VSliderWidth; + + [System.NonSerialized] private RectTransform m_Rect; + private RectTransform rectTransform + { + get + { + if (m_Rect == null) + m_Rect = GetComponent(); + return m_Rect; + } + } + + private RectTransform m_HorizontalScrollbarRect; + private RectTransform m_VerticalScrollbarRect; + + private DrivenRectTransformTracker m_Tracker; + + protected LoopScrollRectBase() + {} + + //==========LoopScrollRect========== + #if UNITY_EDITOR + protected override void Awake() + { + base.Awake(); + if (Application.isPlaying) + { + float value = (reverseDirection ^ (direction == LoopScrollRectDirection.Horizontal)) ? 0 : 1; + if (m_Content != null) + { + Debug.Assert(GetAbsDimension(m_Content.pivot) == value, this); + Debug.Assert(GetAbsDimension(m_Content.anchorMin) == value, this); + Debug.Assert(GetAbsDimension(m_Content.anchorMax) == value, this); + } + if (direction == LoopScrollRectDirection.Vertical) + Debug.Assert(m_Vertical && !m_Horizontal, this); + else + Debug.Assert(!m_Vertical && m_Horizontal, this); + } + } + #endif + + public void ClearCells() + { + if (Application.isPlaying) + { + itemTypeStart = 0; + itemTypeEnd = 0; + itemTypeSize = 0; + totalCount = 0; + for (int i = m_Content.childCount - 1; i >= 0; i--) + { + prefabSource.ReturnObject(m_Content.GetChild(i)); + } + } + } + + public int GetFirstItem(out float offset) + { + if (direction == LoopScrollRectDirection.Vertical) + offset = m_ContentBounds.max.y - m_ViewBounds.max.y; + else + offset = m_ViewBounds.min.x - m_ContentBounds.min.x; + int idx = 0; + if (itemTypeEnd > itemTypeStart) + { + float size = GetSize(m_Content.GetChild(0) as RectTransform); + while (offset - size >= 0 && itemTypeStart + idx + contentConstraintCount < itemTypeEnd) + { + offset -= size; + idx += contentConstraintCount; + size = GetSize(m_Content.GetChild(idx) as RectTransform); + } + } + int item = idx + itemTypeStart; + return item; + } + + public int GetLastItem(out float offset) + { + if (direction == LoopScrollRectDirection.Vertical) + offset = m_ViewBounds.min.y - m_ContentBounds.min.y; + else + offset = m_ContentBounds.max.x - m_ViewBounds.max.x; + int idx = 0; + if (itemTypeEnd > itemTypeStart) + { + int totalChildCount = m_Content.childCount; + float size = GetSize(m_Content.GetChild(totalChildCount - idx - 1) as RectTransform); + while (offset - size >= 0 && itemTypeStart < itemTypeEnd - idx - contentConstraintCount) + { + offset -= size; + idx += contentConstraintCount; + size = GetSize(m_Content.GetChild(totalChildCount - idx - 1) as RectTransform); + } + } + int item = itemTypeEnd - idx; + if (totalCount >= 0 && idx > 0 && item % contentConstraintCount != 0) + { + item = (item / contentConstraintCount) * contentConstraintCount; + } + return item; + } + + public enum ScrollMode + { + /// + /// Scroll specified cell to the beginning of viewport + /// + ToStart, + + /// + /// Scroll specified cell to the center of viewport + /// + ToCenter, + + /// + /// Scroll until specified cell appears in viewport + /// + JustAppear, + } + + public void ScrollToCell(int index, float speed, float offset = 0, ScrollMode mode = ScrollMode.ToStart) + { + if (totalCount >= 0 && (index < 0 || index >= totalCount)) + { + Debug.LogErrorFormat("invalid index {0}", index); + return; + } + if (speed <= 0) + { + Debug.LogErrorFormat("invalid speed {0}", index); + return; + } + StopAllCoroutines(); + StartCoroutine(ScrollToCellCoroutine(index, speed, offset, mode)); + } + + public void ScrollToCellWithinTime(int index, float time, float offset = 0, ScrollMode mode = ScrollMode.ToStart) + { + if (totalCount >= 0 && (index < 0 || index >= totalCount)) + { + Debug.LogErrorFormat("invalid index {0}", index); + return; + } + if (time <= 0) + { + Debug.LogErrorFormat("invalid time {0}", time); + return; + } + if (mode == ScrollMode.JustAppear) + { + Debug.LogErrorFormat("scroll mode {0} not supported yet.", mode); + return; + } + StopAllCoroutines(); + float dist = 0; + float currentOffset = 0; + int currentFirst = reverseDirection ? GetLastItem(out currentOffset) : GetFirstItem(out currentOffset); + + int TargetLine = (index / contentConstraintCount); + int CurrentLine = (currentFirst / contentConstraintCount); + + if (TargetLine == CurrentLine) + { + dist = -currentOffset; + } + else + { + if (sizeHelper != null) + { + dist = GetDimension(sizeHelper.GetItemsSize(currentFirst) - sizeHelper.GetItemsSize(index)) + contentSpacing * (CurrentLine - TargetLine); + dist -= currentOffset; + } + else + { + float elementSize = EstimiateElementSize(); + dist = elementSize * (CurrentLine - TargetLine) + contentSpacing * (CurrentLine - TargetLine); + dist -= currentOffset; + } + } + dist += offset; + if (mode == ScrollMode.ToCenter) + { + float sizeToFill = GetAbsDimension(viewRect.rect.size); + if (sizeHelper != null) + { + sizeToFill -= GetDimension(sizeHelper.GetItemsSize(index)); + } + else + { + float elementSize = EstimiateElementSize(); + sizeToFill -= elementSize; + } + dist += sizeToFill * 0.5f; + } + StartCoroutine(ScrollToCellCoroutine(index, Mathf.Abs(dist) / time, offset, mode)); + } + + IEnumerator ScrollToCellCoroutine(int index, float speed, float offset, ScrollMode mode) + { + bool needMoving = true; + while (needMoving) + { + yield return null; + if (!m_Dragging) + { + float move = 0; + if (index < itemTypeStart) + { + move = -Time.deltaTime * speed; + } + else if (index >= itemTypeEnd) + { + move = Time.deltaTime * speed; + } + else + { + m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size); + var m_ItemBounds = GetBounds4Item(index); + var delta = 0.0f; + if (mode == ScrollMode.ToStart) + { + if (direction == LoopScrollRectDirection.Vertical) + { + delta = reverseDirection ? (m_ViewBounds.min.y - m_ItemBounds.min.y) : (m_ViewBounds.max.y - m_ItemBounds.max.y); + } + else + { + delta = reverseDirection ? (m_ItemBounds.max.x - m_ViewBounds.max.x) : (m_ItemBounds.min.x - m_ViewBounds.min.x); + } + } + else if (mode == ScrollMode.ToCenter) + { + delta = GetDimension(m_ViewBounds.center - m_ItemBounds.center); + } + else // ScrollMode.FirstAppear + { + float min_delta = GetDimension(m_ViewBounds.min - m_ItemBounds.min); + float max_delta = GetDimension(m_ViewBounds.max - m_ItemBounds.max); + if (direction == LoopScrollRectDirection.Vertical) + { + if (min_delta > 0) + { + delta = min_delta; + } + else if(max_delta < 0) + { + delta = max_delta; + } + } + else + { + if (min_delta < 0) + { + delta = min_delta; + } + else if(max_delta > 0) + { + delta = max_delta; + } + } + } + delta += offset; + // check if we cannot move on + if (totalCount >= 0) + { + if (delta > 0 && itemTypeEnd == totalCount) + { + m_ItemBounds = GetBounds4Item(totalCount - 1); + // reach bottom + if ((direction == LoopScrollRectDirection.Vertical && m_ItemBounds.min.y > m_ViewBounds.min.y) || + (direction == LoopScrollRectDirection.Horizontal && m_ItemBounds.max.x < m_ViewBounds.max.x)) + { + needMoving = false; + break; + } + } + else if (delta < 0 && itemTypeStart == 0) + { + m_ItemBounds = GetBounds4Item(0); + if ((direction == LoopScrollRectDirection.Vertical && m_ItemBounds.max.y < m_ViewBounds.max.y) || + (direction == LoopScrollRectDirection.Horizontal && m_ItemBounds.min.x > m_ViewBounds.min.x)) + { + needMoving = false; + break; + } + } + } + + float maxMove = Time.deltaTime * speed; + if (Mathf.Abs(delta) < maxMove) + { + needMoving = false; + move = delta; + } + else + { + move = Mathf.Sign(delta) * maxMove; + } + } + if (move != 0) + { + Vector2 delta = GetVector(move); + m_Content.anchoredPosition += delta; + m_PrevPosition += delta; + m_ContentStartPosition += delta; + UpdateBounds(true); + } + } + } + StopMovement(); + UpdatePrevData(); + } + + protected abstract void ProvideData(Transform transform, int index); + + /// + /// Refresh item data + /// + public void RefreshCells() + { + if (Application.isPlaying && this.isActiveAndEnabled) + { + itemTypeEnd = itemTypeStart; + itemTypeSize = 0; + // recycle items if we can + for (int i = 0; i < m_Content.childCount; i++) + { + if (itemTypeEnd < totalCount || totalCount < 0) + { + ProvideData(m_Content.GetChild(i), itemTypeEnd); + itemTypeEnd++; + itemTypeSize += GetSize(m_Content.GetChild(i).GetComponent()); + } + else + { + prefabSource.ReturnObject(m_Content.GetChild(i)); + i--; + } + } + UpdateBounds(true); + UpdateScrollbars(Vector2.zero); + } + } + + /// + /// Refill cells from endItem at the end while clear existing ones + /// + public void RefillCellsFromEnd(int endItem = 0, float contentOffset = 0) + { + if (!Application.isPlaying) + return; + + itemTypeEnd = reverseDirection ? endItem : totalCount - endItem; + itemTypeStart = itemTypeEnd; + itemTypeSize = 0; + + if (totalCount >= 0 && itemTypeStart % contentConstraintCount != 0) + { + itemTypeStart = (itemTypeStart / contentConstraintCount) * contentConstraintCount; + } + + ReturnToTempPool(!reverseDirection, m_Content.childCount); + + float sizeToFill = GetAbsDimension(viewRect.rect.size) + contentOffset; + float sizeFilled = 0; + // issue #169: fill last line + if (itemTypeStart < itemTypeEnd) + { + itemTypeEnd = itemTypeStart; + float size = NewItemAtEnd(); + if (size >= 0) + { + sizeFilled += size; + } + } + + while (sizeToFill > sizeFilled) + { + float size = NewItemAtStart(); + if (size < 0) + break; + sizeFilled += size; + } + float sizeFilledAtStart = sizeFilled; + + // refill from start in case not full yet + while (sizeToFill > sizeFilled) + { + float size = NewItemAtEnd(); + if (size < 0) + break; + sizeFilled += size; + } + float sizeFilledAtEnd = sizeFilled - sizeFilledAtStart; + + Vector2 pos = m_Content.anchoredPosition; + float padding_dist = GetAbsDimension(new Vector2(m_ContentLeftPadding + m_ContentRightPadding, m_ContentTopPadding + m_ContentBottomPadding)); + float offset = 0; + if (reverseDirection) + offset = Mathf.Max(0, sizeFilledAtEnd + padding_dist - sizeToFill) + contentOffset; + else + offset = Mathf.Max(0, sizeFilledAtStart + padding_dist - sizeToFill); + if (direction == LoopScrollRectDirection.Vertical) + pos.y = reverseDirection ? -offset : offset; + else + pos.x = reverseDirection ? offset : -offset; + m_Content.anchoredPosition = pos; + m_ContentStartPosition = pos; + + ClearTempPool(); + // force build bounds here so scrollbar can access newest bounds + LayoutRebuilder.ForceRebuildLayoutImmediate(m_Content); + Canvas.ForceUpdateCanvases(); + UpdateBounds(false); + UpdateScrollbars(Vector2.zero); + StopMovement(); + UpdatePrevData(); + } + + /// + /// Refill cells with startItem at the beginning while clear existing ones + /// + /// The first item to fill + /// The first item's offset compared to viewBound + public void RefillCells(int startItem = 0, float contentOffset = 0) + { + if (!Application.isPlaying) + return; + + itemTypeStart = reverseDirection ? totalCount - startItem : startItem; + if (totalCount >= 0 && itemTypeStart % contentConstraintCount != 0) + { + itemTypeStart = (itemTypeStart / contentConstraintCount) * contentConstraintCount; + } + itemTypeEnd = itemTypeStart; + itemTypeSize = 0; + + // Don't `Canvas.ForceUpdateCanvases();` here, or it will new/delete cells to change itemTypeStart/End + ReturnToTempPool(reverseDirection, m_Content.childCount); + + float sizeToFill = GetAbsDimension(viewRect.rect.size) + contentOffset; + float sizeFilled = 0; + // m_ViewBounds may be not ready when RefillCells on Start + + while (sizeToFill > sizeFilled) + { + float size = NewItemAtEnd(); + if (size < 0) + break; + sizeFilled += size; + } + float sizeFilledAtEnd = sizeFilled; + + // refill from start in case not full yet + while (sizeToFill > sizeFilled) + { + float size = NewItemAtStart(); + if (size < 0) + break; + sizeFilled += size; + } + float sizeFilledAtStart = sizeFilled - sizeFilledAtEnd; + + Vector2 pos = m_Content.anchoredPosition; + float padding_dist = GetAbsDimension(new Vector2(m_ContentLeftPadding + m_ContentRightPadding, m_ContentTopPadding + m_ContentBottomPadding)); + float offset = 0; + if (reverseDirection) + offset = Mathf.Max(0, sizeFilledAtEnd + padding_dist - sizeToFill); + else + offset = sizeFilledAtStart + contentOffset; + if (direction == LoopScrollRectDirection.Vertical) + pos.y = reverseDirection ? -offset : offset; + else + pos.x = reverseDirection ? offset : -offset; + m_Content.anchoredPosition = pos; + m_ContentStartPosition = pos; + + ClearTempPool(); + // force build bounds here so scrollbar can access newest bounds + LayoutRebuilder.ForceRebuildLayoutImmediate(m_Content); + Canvas.ForceUpdateCanvases(); + UpdateBounds(false); + UpdateScrollbars(Vector2.zero); + StopMovement(); + UpdatePrevData(); + } + + protected float NewItemAtStart() + { + if (totalCount >= 0 && itemTypeStart - contentConstraintCount < 0) + { + return -1; + } + bool includeSpacing = (CurrentLines > 0); + float size = 0; + for (int i = 0; i < contentConstraintCount; i++) + { + itemTypeStart--; + RectTransform newItem = GetFromTempPool(itemTypeStart); + newItem.SetSiblingIndex(deletedItemTypeStart); + size = Mathf.Max(GetSize(newItem, includeSpacing), size); + } + threshold = Mathf.Max(threshold, size * 1.5f); + + if (size > 0) + { + SetDirtyCaching(); + m_HasRebuiltLayout = false; + if (!reverseDirection) + { + Vector2 offset = GetVector(size); + m_Content.anchoredPosition += offset; + m_PrevPosition += offset; + m_ContentStartPosition += offset; + } + itemTypeSize += size; + } + + return size; + } + + protected float DeleteItemAtStart() + { + // special case: when moving or dragging, we cannot simply delete start when we've reached the end + if ((m_Dragging || m_Velocity != Vector2.zero) && totalCount >= 0 && itemTypeEnd >= totalCount - contentConstraintCount) + { + return 0; + } + int availableChilds = m_Content.childCount - deletedItemTypeStart - deletedItemTypeEnd; + Debug.Assert(availableChilds >= 0); + if (availableChilds == 0) + { + return 0; + } + bool includeSpacing = (CurrentLines > 1); + float size = 0; + for (int i = 0; i < contentConstraintCount; i++) + { + RectTransform oldItem = m_Content.GetChild(deletedItemTypeStart) as RectTransform; + size = Mathf.Max(GetSize(oldItem, includeSpacing), size); + ReturnToTempPool(true); + availableChilds--; + itemTypeStart++; + + if (availableChilds == 0) + { + break; + } + } + + if (size > 0) + { + SetDirtyCaching(); + m_HasRebuiltLayout = false; + if (!reverseDirection) + { + Vector2 offset = GetVector(size); + m_Content.anchoredPosition -= offset; + m_PrevPosition -= offset; + m_ContentStartPosition -= offset; + } + itemTypeSize -= size; + } + + return size; + } + + + protected float NewItemAtEnd() + { + if (totalCount >= 0 && itemTypeEnd >= totalCount) + { + return -1; + } + bool includeSpacing = (CurrentLines > 0); + float size = 0; + // issue #4: fill lines to end first + int availableChilds = m_Content.childCount - deletedItemTypeStart - deletedItemTypeEnd; + int count = contentConstraintCount - (availableChilds % contentConstraintCount); + for (int i = 0; i < count; i++) + { + RectTransform newItem = GetFromTempPool(itemTypeEnd); + newItem.SetSiblingIndex(m_Content.childCount - deletedItemTypeEnd - 1); + size = Mathf.Max(GetSize(newItem, includeSpacing), size); + itemTypeEnd++; + if (totalCount >= 0 && itemTypeEnd >= totalCount) + { + break; + } + } + threshold = Mathf.Max(threshold, size * 1.5f); + + if (size > 0) + { + SetDirtyCaching(); + m_HasRebuiltLayout = false; + if (reverseDirection) + { + Vector2 offset = GetVector(size); + m_Content.anchoredPosition -= offset; + m_PrevPosition -= offset; + m_ContentStartPosition -= offset; + } + itemTypeSize += size; + } + + return size; + } + + protected float DeleteItemAtEnd() + { + if ((m_Dragging || m_Velocity != Vector2.zero) && totalCount >= 0 && itemTypeStart < contentConstraintCount) + { + return 0; + } + int availableChilds = m_Content.childCount - deletedItemTypeStart - deletedItemTypeEnd; + Debug.Assert(availableChilds >= 0); + if (availableChilds == 0) + { + return 0; + } + bool includeSpacing = (CurrentLines > 1); + float size = 0; + for (int i = 0; i < contentConstraintCount; i++) + { + RectTransform oldItem = m_Content.GetChild(m_Content.childCount - deletedItemTypeEnd - 1) as RectTransform; + size = Mathf.Max(GetSize(oldItem, includeSpacing), size); + ReturnToTempPool(false); + availableChilds--; + itemTypeEnd--; + if (itemTypeEnd % contentConstraintCount == 0 || availableChilds == 0) + { + break; //just delete the whole row + } + } + + if (size > 0) + { + SetDirtyCaching(); + m_HasRebuiltLayout = false; + if (reverseDirection) + { + Vector2 offset = GetVector(size); + m_Content.anchoredPosition += offset; + m_PrevPosition += offset; + m_ContentStartPosition += offset; + } + itemTypeSize -= size; + } + + return size; + } + + protected int deletedItemTypeStart = 0; + protected int deletedItemTypeEnd = 0; + protected abstract RectTransform GetFromTempPool(int itemIdx); + protected abstract void ReturnToTempPool(bool fromStart, int count = 1); + protected abstract void ClearTempPool(); + + #region Deprecated API + + [Obsolete("SrollToCell(int, float) has been renamed to ScrollToCell(int, float).")] + public void SrollToCell(int index, float speed) + { + ScrollToCell(index, speed); + } + + [Obsolete("SrollToCellWithinTime(int, float) has been renamed to ScrollToCellWithinTime(int, float).")] + public void SrollToCellWithinTime(int index, float time) + { + ScrollToCellWithinTime(index, time); + } + #endregion + //==========LoopScrollRect========== + + public virtual void Rebuild(CanvasUpdate executing) + { + if (executing == CanvasUpdate.Prelayout) + { + UpdateCachedData(); + } + + if (executing == CanvasUpdate.PostLayout) + { + UpdateBounds(); + UpdateScrollbars(Vector2.zero); + UpdatePrevData(); + + m_HasRebuiltLayout = true; + } + } + + public virtual void LayoutComplete() + {} + + public virtual void GraphicUpdateComplete() + {} + + void UpdateCachedData() + { + Transform transform = this.transform; + m_HorizontalScrollbarRect = m_HorizontalScrollbar == null ? null : m_HorizontalScrollbar.transform as RectTransform; + m_VerticalScrollbarRect = m_VerticalScrollbar == null ? null : m_VerticalScrollbar.transform as RectTransform; + + // These are true if either the elements are children, or they don't exist at all. + bool viewIsChild = (viewRect.parent == transform); + bool hScrollbarIsChild = (!m_HorizontalScrollbarRect || m_HorizontalScrollbarRect.parent == transform); + bool vScrollbarIsChild = (!m_VerticalScrollbarRect || m_VerticalScrollbarRect.parent == transform); + bool allAreChildren = (viewIsChild && hScrollbarIsChild && vScrollbarIsChild); + + m_HSliderExpand = allAreChildren && m_HorizontalScrollbarRect && horizontalScrollbarVisibility == ScrollbarVisibility.AutoHideAndExpandViewport; + m_VSliderExpand = allAreChildren && m_VerticalScrollbarRect && verticalScrollbarVisibility == ScrollbarVisibility.AutoHideAndExpandViewport; + m_HSliderHeight = (m_HorizontalScrollbarRect == null ? 0 : m_HorizontalScrollbarRect.rect.height); + m_VSliderWidth = (m_VerticalScrollbarRect == null ? 0 : m_VerticalScrollbarRect.rect.width); + } + + protected override void OnEnable() + { + base.OnEnable(); + + if (m_HorizontalScrollbar) + m_HorizontalScrollbar.onValueChanged.AddListener(SetHorizontalNormalizedPosition); + if (m_VerticalScrollbar) + m_VerticalScrollbar.onValueChanged.AddListener(SetVerticalNormalizedPosition); + + CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this); + SetDirty(); + } + + protected override void OnDisable() + { + CanvasUpdateRegistry.UnRegisterCanvasElementForRebuild(this); + + if (m_HorizontalScrollbar) + m_HorizontalScrollbar.onValueChanged.RemoveListener(SetHorizontalNormalizedPosition); + if (m_VerticalScrollbar) + m_VerticalScrollbar.onValueChanged.RemoveListener(SetVerticalNormalizedPosition); + + m_Dragging = false; + m_Scrolling = false; + m_HasRebuiltLayout = false; + m_Tracker.Clear(); + m_Velocity = Vector2.zero; + LayoutRebuilder.MarkLayoutForRebuild(rectTransform); + base.OnDisable(); + } + + /// + /// See member in base class. + /// + /// + /// + /// using UnityEngine; + /// using System.Collections; + /// using UnityEngine.UI; // Required when Using UI elements. + /// + /// public class ExampleClass : MonoBehaviour + /// { + /// public ScrollRect myScrollRect; + /// + /// public void Start() + /// { + /// //Checks if the ScrollRect called "myScrollRect" is active. + /// if (myScrollRect.IsActive()) + /// { + /// Debug.Log("The Scroll Rect is active!"); + /// } + /// } + /// } + /// + /// + public override bool IsActive() + { + return base.IsActive() && m_Content != null; + } + + private void EnsureLayoutHasRebuilt() + { + if (!m_HasRebuiltLayout && !CanvasUpdateRegistry.IsRebuildingLayout()) + Canvas.ForceUpdateCanvases(); + } + + /// + /// Sets the velocity to zero on both axes so the content stops moving. + /// + public virtual void StopMovement() + { + m_Velocity = Vector2.zero; + } + + public virtual void OnScroll(PointerEventData data) + { + if (!IsActive()) + return; + + EnsureLayoutHasRebuilt(); + UpdateBounds(); + + Vector2 delta = data.scrollDelta; + // Down is positive for scroll events, while in UI system up is positive. + delta.y *= -1; + if (vertical && !horizontal) + { + if (Mathf.Abs(delta.x) > Mathf.Abs(delta.y)) + delta.y = delta.x; + delta.x = 0; + } + if (horizontal && !vertical) + { + if (Mathf.Abs(delta.y) > Mathf.Abs(delta.x)) + delta.x = delta.y; + delta.y = 0; + } + + if (data.IsScrolling()) + m_Scrolling = true; + + Vector2 position = m_Content.anchoredPosition; + position += delta * m_ScrollSensitivity; + if (m_MovementType == MovementType.Clamped) + position += CalculateOffset(position - m_Content.anchoredPosition); + + SetContentAnchoredPosition(position); + UpdateBounds(); + } + + public virtual void OnInitializePotentialDrag(PointerEventData eventData) + { + if (eventData.button != PointerEventData.InputButton.Left) + return; + + m_Velocity = Vector2.zero; + } + + /// + /// Handling for when the content is beging being dragged. + /// + /// + /// + /// using UnityEngine; + /// using System.Collections; + /// using UnityEngine.EventSystems; // Required when using event data + /// + /// public class ExampleClass : MonoBehaviour, IBeginDragHandler // required interface when using the OnBeginDrag method. + /// { + /// //Do this when the user starts dragging the element this script is attached to.. + /// public void OnBeginDrag(PointerEventData data) + /// { + /// Debug.Log("They started dragging " + this.name); + /// } + /// } + /// + /// + public virtual void OnBeginDrag(PointerEventData eventData) + { + if (eventData.button != PointerEventData.InputButton.Left) + return; + + if (!IsActive()) + return; + + UpdateBounds(); + + m_PointerStartLocalCursor = Vector2.zero; + RectTransformUtility.ScreenPointToLocalPointInRectangle(viewRect, eventData.position, eventData.pressEventCamera, out m_PointerStartLocalCursor); + m_ContentStartPosition = m_Content.anchoredPosition; + m_Dragging = true; + } + + /// + /// Handling for when the content has finished being dragged. + /// + /// + /// + /// using UnityEngine; + /// using System.Collections; + /// using UnityEngine.EventSystems; // Required when using event data + /// + /// public class ExampleClass : MonoBehaviour, IEndDragHandler // required interface when using the OnEndDrag method. + /// { + /// //Do this when the user stops dragging this UI Element. + /// public void OnEndDrag(PointerEventData data) + /// { + /// Debug.Log("Stopped dragging " + this.name + "!"); + /// } + /// } + /// + /// + public virtual void OnEndDrag(PointerEventData eventData) + { + if (eventData.button != PointerEventData.InputButton.Left) + return; + + m_Dragging = false; + } + + /// + /// Handling for when the content is dragged. + /// + /// + /// + /// using UnityEngine; + /// using System.Collections; + /// using UnityEngine.EventSystems; // Required when using event data + /// + /// public class ExampleClass : MonoBehaviour, IDragHandler // required interface when using the OnDrag method. + /// { + /// //Do this while the user is dragging this UI Element. + /// public void OnDrag(PointerEventData data) + /// { + /// Debug.Log("Currently dragging " + this.name); + /// } + /// } + /// + /// + public virtual void OnDrag(PointerEventData eventData) + { + if (!m_Dragging) + return; + + if (eventData.button != PointerEventData.InputButton.Left) + return; + + if (!IsActive()) + return; + + Vector2 localCursor; + if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(viewRect, eventData.position, eventData.pressEventCamera, out localCursor)) + return; + + UpdateBounds(); + + var pointerDelta = localCursor - m_PointerStartLocalCursor; + Vector2 position = m_ContentStartPosition + pointerDelta; + + // Offset to get content into place in the view. + Vector2 offset = CalculateOffset(position - m_Content.anchoredPosition); + position += offset; + if (m_MovementType == MovementType.Elastic) + { + if (offset.x != 0) + position.x = position.x - RubberDelta(offset.x, m_ViewBounds.size.x); + if (offset.y != 0) + position.y = position.y - RubberDelta(offset.y, m_ViewBounds.size.y); + } + + SetContentAnchoredPosition(position); + } + + /// + /// Sets the anchored position of the content. + /// + protected virtual void SetContentAnchoredPosition(Vector2 position) + { + if (!m_Horizontal) + position.x = m_Content.anchoredPosition.x; + if (!m_Vertical) + position.y = m_Content.anchoredPosition.y; + + //==========LoopScrollRect========== + if ((position - m_Content.anchoredPosition).sqrMagnitude > 0.001f) + { + m_Content.anchoredPosition = position; + UpdateBounds(true); + } + //==========LoopScrollRect========== + } + + protected virtual void LateUpdate() + { + if (!m_Content) + return; + + EnsureLayoutHasRebuilt(); + UpdateBounds(); + float deltaTime = Time.unscaledDeltaTime; + Vector2 offset = CalculateOffset(Vector2.zero); + if (!m_Dragging && (offset != Vector2.zero || m_Velocity != Vector2.zero)) + { + Vector2 position = m_Content.anchoredPosition; + for (int axis = 0; axis < 2; axis++) + { + // Apply spring physics if movement is elastic and content has an offset from the view. + if (m_MovementType == MovementType.Elastic && offset[axis] != 0) + { + float speed = m_Velocity[axis]; + float smoothTime = m_Elasticity; + if (m_Scrolling) + smoothTime *= 3.0f; + position[axis] = Mathf.SmoothDamp(m_Content.anchoredPosition[axis], m_Content.anchoredPosition[axis] + offset[axis], ref speed, smoothTime, Mathf.Infinity, deltaTime); + if (Mathf.Abs(speed) < 1) + speed = 0; + m_Velocity[axis] = speed; + } + // Else move content according to velocity with deceleration applied. + else if (m_Inertia) + { + m_Velocity[axis] *= Mathf.Pow(m_DecelerationRate, deltaTime); + if (Mathf.Abs(m_Velocity[axis]) < 1) + m_Velocity[axis] = 0; + position[axis] += m_Velocity[axis] * deltaTime; + } + // If we have neither elaticity or friction, there shouldn't be any velocity. + else + { + m_Velocity[axis] = 0; + } + } + + if (m_MovementType == MovementType.Clamped) + { + offset = CalculateOffset(position - m_Content.anchoredPosition); + position += offset; + } + + SetContentAnchoredPosition(position); + } + + if (m_Dragging && m_Inertia) + { + Vector3 newVelocity = (m_Content.anchoredPosition - m_PrevPosition) / deltaTime; + m_Velocity = Vector3.Lerp(m_Velocity, newVelocity, deltaTime * 10); + } + + if (m_ViewBounds != m_PrevViewBounds || m_ContentBounds != m_PrevContentBounds || m_Content.anchoredPosition != m_PrevPosition) + { + UpdateScrollbars(offset); + #if UNITY_2017_1_OR_NEWER + UISystemProfilerApi.AddMarker("ScrollRect.value", this); + #endif + m_OnValueChanged.Invoke(normalizedPosition); + UpdatePrevData(); + } + UpdateScrollbarVisibility(); + m_Scrolling = false; + } + + /// + /// Helper function to update the previous data fields on a ScrollRect. Call this before you change data in the ScrollRect. + /// + protected void UpdatePrevData() + { + if (m_Content == null) + m_PrevPosition = Vector2.zero; + else + m_PrevPosition = m_Content.anchoredPosition; + m_PrevViewBounds = m_ViewBounds; + m_PrevContentBounds = m_ContentBounds; + } + + //==========LoopScrollRect========== + protected float EstimiateElementSize() + { + int childCount = m_Content.childCount; + if (CurrentLines == 0) + { + return 0; + } + float elementSize = (itemTypeSize - contentSpacing * (CurrentLines - 1)) / CurrentLines; + return elementSize; + } + + public void GetHorizonalOffsetAndSize(out float totalSize, out float offset) + { + float paddingSize = m_ContentLeftPadding + m_ContentRightPadding; + if (sizeHelper != null) + { + totalSize = sizeHelper.GetItemsSize(TotalLines).x + contentSpacing * (TotalLines - 1) + paddingSize; + offset = m_ContentBounds.min.x - sizeHelper.GetItemsSize(StartLine).x - contentSpacing * StartLine; + } + else + { + float elementSize = EstimiateElementSize(); + totalSize = elementSize * TotalLines + contentSpacing * (TotalLines - 1) + paddingSize; + offset = m_ContentBounds.min.x - elementSize * StartLine - contentSpacing * StartLine; + } + } + + public void GetVerticalOffsetAndSize(out float totalSize, out float offset) + { + float paddingSize = m_ContentTopPadding + m_ContentBottomPadding; + if (sizeHelper != null) + { + totalSize = sizeHelper.GetItemsSize(TotalLines).y + contentSpacing * (TotalLines - 1) + paddingSize; + offset = m_ContentBounds.max.y + sizeHelper.GetItemsSize(StartLine).y + contentSpacing * StartLine; + } + else + { + float elementSize = EstimiateElementSize(); + totalSize = elementSize * TotalLines + contentSpacing * (TotalLines - 1) + paddingSize; + offset = m_ContentBounds.max.y + elementSize * StartLine + contentSpacing * StartLine; + } + } + //==========LoopScrollRect========== + + private void UpdateScrollbars(Vector2 offset) + { + if (m_HorizontalScrollbar) + { + //==========LoopScrollRect========== + if (m_ContentBounds.size.x > 0 && totalCount > 0) + { + float totalSize, _; + GetHorizonalOffsetAndSize(out totalSize, out _); + m_HorizontalScrollbar.size = Mathf.Clamp01((m_ViewBounds.size.x - Mathf.Abs(offset.x)) / totalSize); + } + //==========LoopScrollRect========== + else + m_HorizontalScrollbar.size = 1; + + //==========LoopScrollRect========== + m_HorizontalScrollbar.SetValueWithoutNotify(horizontalNormalizedPosition); + //==========LoopScrollRect========== + } + + if (m_VerticalScrollbar) + { + //==========LoopScrollRect========== + if (m_ContentBounds.size.y > 0 && totalCount > 0) + { + float totalSize, _; + GetVerticalOffsetAndSize(out totalSize, out _); + m_VerticalScrollbar.size = Mathf.Clamp01((m_ViewBounds.size.y - Mathf.Abs(offset.y)) / totalSize); + } + //==========LoopScrollRect========== + else + m_VerticalScrollbar.size = 1; + + //==========LoopScrollRect========== + m_VerticalScrollbar.SetValueWithoutNotify(verticalNormalizedPosition); + //==========LoopScrollRect========== + } + } + + /// + /// The scroll position as a Vector2 between (0,0) and (1,1) with (0,0) being the lower left corner. + /// + /// + /// + /// using UnityEngine; + /// using System.Collections; + /// using UnityEngine.UI; // Required when Using UI elements. + /// + /// public class ExampleClass : MonoBehaviour + /// { + /// public ScrollRect myScrollRect; + /// public Vector2 myPosition = new Vector2(0.5f, 0.5f); + /// + /// public void Start() + /// { + /// //Change the current scroll position. + /// myScrollRect.normalizedPosition = myPosition; + /// } + /// } + /// + /// + public Vector2 normalizedPosition + { + get + { + return new Vector2(horizontalNormalizedPosition, verticalNormalizedPosition); + } + set + { + SetNormalizedPosition(value.x, 0); + SetNormalizedPosition(value.y, 1); + } + } + + /// + /// The horizontal scroll position as a value between 0 and 1, with 0 being at the left. + /// + /// + /// + /// using UnityEngine; + /// using System.Collections; + /// using UnityEngine.UI; // Required when Using UI elements. + /// + /// public class ExampleClass : MonoBehaviour + /// { + /// public ScrollRect myScrollRect; + /// public Scrollbar newScrollBar; + /// + /// public void Start() + /// { + /// //Change the current horizontal scroll position. + /// myScrollRect.horizontalNormalizedPosition = 0.5f; + /// } + /// } + /// + /// + public float horizontalNormalizedPosition + { + get + { + UpdateBounds(); + //==========LoopScrollRect========== + if (totalCount > 0 && itemTypeEnd > itemTypeStart) + { + float totalSize, offset; + GetHorizonalOffsetAndSize(out totalSize, out offset); + + if (totalSize <= m_ViewBounds.size.x) + return (m_ViewBounds.min.x > offset) ? 1 : 0; + return (m_ViewBounds.min.x - offset) / (totalSize - m_ViewBounds.size.x); + } + else + return 0.5f; + //==========LoopScrollRect========== + } + set + { + SetNormalizedPosition(value, 0); + } + } + + /// + /// The vertical scroll position as a value between 0 and 1, with 0 being at the bottom. + /// + /// + /// + /// using UnityEngine; + /// using System.Collections; + /// using UnityEngine.UI; // Required when Using UI elements. + /// + /// public class ExampleClass : MonoBehaviour + /// { + /// public ScrollRect myScrollRect; + /// public Scrollbar newScrollBar; + /// + /// public void Start() + /// { + /// //Change the current vertical scroll position. + /// myScrollRect.verticalNormalizedPosition = 0.5f; + /// } + /// } + /// + /// + + public float verticalNormalizedPosition + { + get + { + UpdateBounds(); + //==========LoopScrollRect========== + if (totalCount > 0 && itemTypeEnd > itemTypeStart) + { + float totalSize, offset; + GetVerticalOffsetAndSize(out totalSize, out offset); + + if (totalSize <= m_ViewBounds.size.y) + return (offset > m_ViewBounds.max.y) ? 1 : 0; + return (offset - m_ViewBounds.max.y) / (totalSize - m_ViewBounds.size.y); + } + else + return 0.5f; + //==========LoopScrollRect========== + } + set + { + SetNormalizedPosition(value, 1); + } + } + + private void SetHorizontalNormalizedPosition(float value) { SetNormalizedPosition(value, 0); } + private void SetVerticalNormalizedPosition(float value) { SetNormalizedPosition(value, 1); } + + /// + /// >Set the horizontal or vertical scroll position as a value between 0 and 1, with 0 being at the left or at the bottom. + /// + /// The position to set, between 0 and 1. + /// The axis to set: 0 for horizontal, 1 for vertical. + protected virtual void SetNormalizedPosition(float value, int axis) + { + //==========LoopScrollRect========== + if (totalCount <= 0 || itemTypeEnd <= itemTypeStart) + return; + //==========LoopScrollRect========== + + EnsureLayoutHasRebuilt(); + UpdateBounds(); + + //==========LoopScrollRect========== + float totalSize, offset; + float newAnchoredPosition = m_Content.anchoredPosition[axis]; + if (axis == 0) + { + GetHorizonalOffsetAndSize(out totalSize, out offset); + + if (totalSize >= m_ViewBounds.size.x) + { + newAnchoredPosition += m_ViewBounds.min.x - value * (totalSize - m_ViewBounds.size.x) - offset; + } + } + else + { + GetVerticalOffsetAndSize(out totalSize, out offset); + + if (totalSize >= m_ViewBounds.size.y) + { + newAnchoredPosition -= offset - value * (totalSize - m_ViewBounds.size.y) - m_ViewBounds.max.y; + } + } + //==========LoopScrollRect========== + + Vector3 anchoredPosition = m_Content.anchoredPosition; + if (Mathf.Abs(anchoredPosition[axis] - newAnchoredPosition) > 0.01f) + { + anchoredPosition[axis] = newAnchoredPosition; + m_Content.anchoredPosition = anchoredPosition; + m_Velocity[axis] = 0; + UpdateBounds(true); //==========LoopScrollRect========== + } + } + + private static float RubberDelta(float overStretching, float viewSize) + { + return (1 - (1 / ((Mathf.Abs(overStretching) * 0.55f / viewSize) + 1))) * viewSize * Mathf.Sign(overStretching); + } + + protected override void OnRectTransformDimensionsChange() + { + SetDirty(); + if (isActiveAndEnabled) + { + UpdateBounds(true); + } + } + + private bool hScrollingNeeded + { + get + { + if (Application.isPlaying) + return m_ContentBounds.size.x > m_ViewBounds.size.x + 0.01f; + return true; + } + } + private bool vScrollingNeeded + { + get + { + if (Application.isPlaying) + return m_ContentBounds.size.y > m_ViewBounds.size.y + 0.01f; + return true; + } + } + + /// + /// Called by the layout system. + /// + public virtual void CalculateLayoutInputHorizontal() {} + + /// + /// Called by the layout system. + /// + public virtual void CalculateLayoutInputVertical() {} + + /// + /// Called by the layout system. + /// + public virtual float minWidth { get { return -1; } } + /// + /// Called by the layout system. + /// + public virtual float preferredWidth { get { return -1; } } + /// + /// Called by the layout system. + /// + public virtual float flexibleWidth { get { return -1; } } + + /// + /// Called by the layout system. + /// + public virtual float minHeight { get { return -1; } } + /// + /// Called by the layout system. + /// + public virtual float preferredHeight { get { return -1; } } + /// + /// Called by the layout system. + /// + public virtual float flexibleHeight { get { return -1; } } + + /// + /// Called by the layout system. + /// + public virtual int layoutPriority { get { return -1; } } + + public virtual void SetLayoutHorizontal() + { + m_Tracker.Clear(); + + if (m_HSliderExpand || m_VSliderExpand) + { + m_Tracker.Add(this, viewRect, + DrivenTransformProperties.Anchors | + DrivenTransformProperties.SizeDelta | + DrivenTransformProperties.AnchoredPosition); + + // Make view full size to see if content fits. + viewRect.anchorMin = Vector2.zero; + viewRect.anchorMax = Vector2.one; + viewRect.sizeDelta = Vector2.zero; + viewRect.anchoredPosition = Vector2.zero; + + // Recalculate content layout with this size to see if it fits when there are no scrollbars. + LayoutRebuilder.ForceRebuildLayoutImmediate(m_Content); + m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size); + m_ContentBounds = GetBounds(); + } + + // If it doesn't fit vertically, enable vertical scrollbar and shrink view horizontally to make room for it. + if (m_VSliderExpand && vScrollingNeeded) + { + viewRect.sizeDelta = new Vector2(-(m_VSliderWidth + m_VerticalScrollbarSpacing), viewRect.sizeDelta.y); + + // Recalculate content layout with this size to see if it fits vertically + // when there is a vertical scrollbar (which may reflowed the content to make it taller). + LayoutRebuilder.ForceRebuildLayoutImmediate(m_Content); + m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size); + m_ContentBounds = GetBounds(); + } + + // If it doesn't fit horizontally, enable horizontal scrollbar and shrink view vertically to make room for it. + if (m_HSliderExpand && hScrollingNeeded) + { + viewRect.sizeDelta = new Vector2(viewRect.sizeDelta.x, -(m_HSliderHeight + m_HorizontalScrollbarSpacing)); + m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size); + m_ContentBounds = GetBounds(); + } + + // If the vertical slider didn't kick in the first time, and the horizontal one did, + // we need to check again if the vertical slider now needs to kick in. + // If it doesn't fit vertically, enable vertical scrollbar and shrink view horizontally to make room for it. + if (m_VSliderExpand && vScrollingNeeded && viewRect.sizeDelta.x == 0 && viewRect.sizeDelta.y < 0) + { + viewRect.sizeDelta = new Vector2(-(m_VSliderWidth + m_VerticalScrollbarSpacing), viewRect.sizeDelta.y); + } + } + + public virtual void SetLayoutVertical() + { + UpdateScrollbarLayout(); + m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size); + m_ContentBounds = GetBounds(); + } + + void UpdateScrollbarVisibility() + { + UpdateOneScrollbarVisibility(vScrollingNeeded, m_Vertical, m_VerticalScrollbarVisibility, m_VerticalScrollbar); + UpdateOneScrollbarVisibility(hScrollingNeeded, m_Horizontal, m_HorizontalScrollbarVisibility, m_HorizontalScrollbar); + } + + private static void UpdateOneScrollbarVisibility(bool xScrollingNeeded, bool xAxisEnabled, ScrollbarVisibility scrollbarVisibility, Scrollbar scrollbar) + { + if (scrollbar) + { + if (scrollbarVisibility == ScrollbarVisibility.Permanent) + { + if (scrollbar.gameObject.activeSelf != xAxisEnabled) + scrollbar.gameObject.SetActive(xAxisEnabled); + } + else + { + if (scrollbar.gameObject.activeSelf != xScrollingNeeded) + scrollbar.gameObject.SetActive(xScrollingNeeded); + } + } + } + + void UpdateScrollbarLayout() + { + if (m_VSliderExpand && m_HorizontalScrollbar) + { + m_Tracker.Add(this, m_HorizontalScrollbarRect, + DrivenTransformProperties.AnchorMinX | + DrivenTransformProperties.AnchorMaxX | + DrivenTransformProperties.SizeDeltaX | + DrivenTransformProperties.AnchoredPositionX); + m_HorizontalScrollbarRect.anchorMin = new Vector2(0, m_HorizontalScrollbarRect.anchorMin.y); + m_HorizontalScrollbarRect.anchorMax = new Vector2(1, m_HorizontalScrollbarRect.anchorMax.y); + m_HorizontalScrollbarRect.anchoredPosition = new Vector2(0, m_HorizontalScrollbarRect.anchoredPosition.y); + if (vScrollingNeeded) + m_HorizontalScrollbarRect.sizeDelta = new Vector2(-(m_VSliderWidth + m_VerticalScrollbarSpacing), m_HorizontalScrollbarRect.sizeDelta.y); + else + m_HorizontalScrollbarRect.sizeDelta = new Vector2(0, m_HorizontalScrollbarRect.sizeDelta.y); + } + + if (m_HSliderExpand && m_VerticalScrollbar) + { + m_Tracker.Add(this, m_VerticalScrollbarRect, + DrivenTransformProperties.AnchorMinY | + DrivenTransformProperties.AnchorMaxY | + DrivenTransformProperties.SizeDeltaY | + DrivenTransformProperties.AnchoredPositionY); + m_VerticalScrollbarRect.anchorMin = new Vector2(m_VerticalScrollbarRect.anchorMin.x, 0); + m_VerticalScrollbarRect.anchorMax = new Vector2(m_VerticalScrollbarRect.anchorMax.x, 1); + m_VerticalScrollbarRect.anchoredPosition = new Vector2(m_VerticalScrollbarRect.anchoredPosition.x, 0); + if (hScrollingNeeded) + m_VerticalScrollbarRect.sizeDelta = new Vector2(m_VerticalScrollbarRect.sizeDelta.x, -(m_HSliderHeight + m_HorizontalScrollbarSpacing)); + else + m_VerticalScrollbarRect.sizeDelta = new Vector2(m_VerticalScrollbarRect.sizeDelta.x, 0); + } + } + + /// + /// Calculate the bounds the ScrollRect should be using. + /// + protected void UpdateBounds(bool updateItems = false) //==========LoopScrollRect========== + { + m_ViewBounds = new Bounds(viewRect.rect.center, viewRect.rect.size); + m_ContentBounds = GetBounds(); + + if (m_Content == null) + return; + + // ============LoopScrollRect============ + // Don't do this in Rebuild. Make use of ContentBounds before Adjust here. + if (!m_HasRebuiltLayout) + { + updateItems = false; + } + if (Application.isPlaying && updateItems && UpdateItems(ref m_ViewBounds, ref m_ContentBounds)) + { + EnsureLayoutHasRebuilt(); + m_ContentBounds = GetBounds(); + } + // ============LoopScrollRect============ + + Vector3 contentSize = m_ContentBounds.size; + Vector3 contentPos = m_ContentBounds.center; + var contentPivot = m_Content.pivot; + AdjustBounds(ref m_ViewBounds, ref contentPivot, ref contentSize, ref contentPos); + m_ContentBounds.size = contentSize; + m_ContentBounds.center = contentPos; + + if (movementType == MovementType.Clamped) + { + // Adjust content so that content bounds bottom (right side) is never higher (to the left) than the view bounds bottom (right side). + // top (left side) is never lower (to the right) than the view bounds top (left side). + // All this can happen if content has shrunk. + // This works because content size is at least as big as view size (because of the call to InternalUpdateBounds above). + Vector2 delta = Vector2.zero; + if (m_ViewBounds.max.x > m_ContentBounds.max.x) + { + delta.x = Math.Min(m_ViewBounds.min.x - m_ContentBounds.min.x, m_ViewBounds.max.x - m_ContentBounds.max.x); + } + else if (m_ViewBounds.min.x < m_ContentBounds.min.x) + { + delta.x = Math.Max(m_ViewBounds.min.x - m_ContentBounds.min.x, m_ViewBounds.max.x - m_ContentBounds.max.x); + } + + if (m_ViewBounds.min.y < m_ContentBounds.min.y) + { + delta.y = Math.Max(m_ViewBounds.min.y - m_ContentBounds.min.y, m_ViewBounds.max.y - m_ContentBounds.max.y); + } + else if (m_ViewBounds.max.y > m_ContentBounds.max.y) + { + delta.y = Math.Min(m_ViewBounds.min.y - m_ContentBounds.min.y, m_ViewBounds.max.y - m_ContentBounds.max.y); + } + if (delta.sqrMagnitude > float.Epsilon) + { + contentPos = m_Content.anchoredPosition + delta; + if (!m_Horizontal) + contentPos.x = m_Content.anchoredPosition.x; + if (!m_Vertical) + contentPos.y = m_Content.anchoredPosition.y; + AdjustBounds(ref m_ViewBounds, ref contentPivot, ref contentSize, ref contentPos); + } + } + } + + internal static void AdjustBounds(ref Bounds viewBounds, ref Vector2 contentPivot, ref Vector3 contentSize, ref Vector3 contentPos) + { + // Make sure content bounds are at least as large as view by adding padding if not. + // One might think at first that if the content is smaller than the view, scrolling should be allowed. + // However, that's not how scroll views normally work. + // Scrolling is *only* possible when content is *larger* than view. + // We use the pivot of the content rect to decide in which directions the content bounds should be expanded. + // E.g. if pivot is at top, bounds are expanded downwards. + // This also works nicely when ContentSizeFitter is used on the content. + Vector3 excess = viewBounds.size - contentSize; + if (excess.x > 0) + { + contentPos.x -= excess.x * (contentPivot.x - 0.5f); + contentSize.x = viewBounds.size.x; + } + if (excess.y > 0) + { + contentPos.y -= excess.y * (contentPivot.y - 0.5f); + contentSize.y = viewBounds.size.y; + } + } + + private readonly Vector3[] m_Corners = new Vector3[4]; + private Bounds GetBounds() + { + if (m_Content == null) + return new Bounds(); + m_Content.GetWorldCorners(m_Corners); + var viewWorldToLocalMatrix = viewRect.worldToLocalMatrix; + return InternalGetBounds(m_Corners, ref viewWorldToLocalMatrix); + } + + internal static Bounds InternalGetBounds(Vector3[] corners, ref Matrix4x4 viewWorldToLocalMatrix) + { + var vMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); + var vMax = new Vector3(float.MinValue, float.MinValue, float.MinValue); + + for (int j = 0; j < 4; j++) + { + Vector3 v = viewWorldToLocalMatrix.MultiplyPoint3x4(corners[j]); + vMin = Vector3.Min(v, vMin); + vMax = Vector3.Max(v, vMax); + } + + var bounds = new Bounds(vMin, Vector3.zero); + bounds.Encapsulate(vMax); + return bounds; + } + + //==========LoopScrollRect========== + private Bounds GetBounds4Item(int index) + { + if (m_Content == null) + return new Bounds(); + + int offset = index - itemTypeStart; + if (offset < 0 || offset >= m_Content.childCount) + return new Bounds(); + + var rt = m_Content.GetChild(offset) as RectTransform; + if (rt == null) + return new Bounds(); + rt.GetWorldCorners(m_Corners); + + var viewWorldToLocalMatrix = viewRect.worldToLocalMatrix; + return InternalGetBounds(m_Corners, ref viewWorldToLocalMatrix); + } + //==========LoopScrollRect========== + + private Vector2 CalculateOffset(Vector2 delta) + { + //==========LoopScrollRect========== + if (totalCount < 0 || movementType == MovementType.Unrestricted) + return delta; + + Bounds contentBound = m_ContentBounds; + if (m_Horizontal) + { + float totalSize, offset; + GetHorizonalOffsetAndSize(out totalSize, out offset); + + Vector3 center = contentBound.center; + center.x = offset; + contentBound.Encapsulate(center); + center.x = offset + totalSize; + contentBound.Encapsulate(center); + } + if (m_Vertical) + { + float totalSize, offset; + GetVerticalOffsetAndSize(out totalSize, out offset); + + Vector3 center = contentBound.center; + center.y = offset; + contentBound.Encapsulate(center); + center.y = offset - totalSize; + contentBound.Encapsulate(center); + } + //==========LoopScrollRect========== + return InternalCalculateOffset(ref m_ViewBounds, ref contentBound, m_Horizontal, m_Vertical, m_MovementType, ref delta); + } + + internal static Vector2 InternalCalculateOffset(ref Bounds viewBounds, ref Bounds contentBounds, bool horizontal, bool vertical, MovementType movementType, ref Vector2 delta) + { + Vector2 offset = Vector2.zero; + if (movementType == MovementType.Unrestricted) + return offset; + + Vector2 min = contentBounds.min; + Vector2 max = contentBounds.max; + + // min/max offset extracted to check if approximately 0 and avoid recalculating layout every frame (case 1010178) + + if (horizontal) + { + min.x += delta.x; + max.x += delta.x; + + float maxOffset = viewBounds.max.x - max.x; + float minOffset = viewBounds.min.x - min.x; + + if (minOffset < -0.001f) + offset.x = minOffset; + else if (maxOffset > 0.001f) + offset.x = maxOffset; + } + + if (vertical) + { + min.y += delta.y; + max.y += delta.y; + + float maxOffset = viewBounds.max.y - max.y; + float minOffset = viewBounds.min.y - min.y; + + if (maxOffset > 0.001f) + offset.y = maxOffset; + else if (minOffset < -0.001f) + offset.y = minOffset; + } + + return offset; + } + + /// + /// Override to alter or add to the code that keeps the appearance of the scroll rect synced with its data. + /// + protected void SetDirty() + { + if (!IsActive()) + return; + + LayoutRebuilder.MarkLayoutForRebuild(rectTransform); + } + + /// + /// Override to alter or add to the code that caches data to avoid repeated heavy operations. + /// + protected void SetDirtyCaching() + { + if (!IsActive()) + return; + + CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this); + LayoutRebuilder.MarkLayoutForRebuild(rectTransform); + } + /* We don't need `[ExecuteAlways]` so comment here + #if UNITY_EDITOR + protected override void OnValidate() + { + SetDirtyCaching(); + } + + #endif + */ + } +} \ No newline at end of file diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRectBase.cs.meta b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRectBase.cs.meta new file mode 100644 index 0000000..150b264 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRectBase.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 33aaabb8aa0854047a50d2d2b0c6f1a5 +timeCreated: 1439395663 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRectMulti.cs b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRectMulti.cs new file mode 100644 index 0000000..3ae5712 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRectMulti.cs @@ -0,0 +1,56 @@ +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.EventSystems; +using System; +using System.Collections; +using System.Collections.Generic; + +namespace UnityEngine.UI +{ + public abstract class LoopScrollRectMulti : LoopScrollRectBase + { + [HideInInspector] + [NonSerialized] + public LoopScrollMultiDataSource dataSource = null; + + protected override void ProvideData(Transform transform, int index) + { + dataSource.ProvideData(transform, index); + } + + // Multi Data Source cannot support TempPool + protected override RectTransform GetFromTempPool(int itemIdx) + { + RectTransform nextItem = prefabSource.GetObject(itemIdx).transform as RectTransform; + nextItem.transform.SetParent(m_Content, false); + nextItem.gameObject.SetActive(true); + + ProvideData(nextItem, itemIdx); + return nextItem; + } + + protected override void ReturnToTempPool(bool fromStart, int count) + { + Debug.Assert(m_Content.childCount >= count); + if (fromStart) + { + for (int i = count - 1; i >= 0; i--) + { + prefabSource.ReturnObject(m_Content.GetChild(i)); + } + } + else + { + int t = m_Content.childCount - count; + for (int i = m_Content.childCount - 1; i >= t; i--) + { + prefabSource.ReturnObject(m_Content.GetChild(i)); + } + } + } + + protected override void ClearTempPool() + { + } + } +} \ No newline at end of file diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRectMulti.cs.meta b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRectMulti.cs.meta new file mode 100644 index 0000000..37aadf9 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollRectMulti.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1bb4b17b11dd527499b49566928fed17 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollSizeHelper.cs b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollSizeHelper.cs new file mode 100644 index 0000000..3fb910d --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollSizeHelper.cs @@ -0,0 +1,11 @@ +using UnityEngine; +using System.Collections; + +namespace UnityEngine.UI +{ + // optional class for better scroll support + public interface LoopScrollSizeHelper + { + Vector2 GetItemsSize(int itemsCount); + } +} diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollSizeHelper.cs.meta b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollSizeHelper.cs.meta new file mode 100644 index 0000000..09b51b5 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollSizeHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 34053817472810d49a0a82b79338dde5 +timeCreated: 1500356133 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollSizeUtils.cs b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollSizeUtils.cs new file mode 100644 index 0000000..af43c57 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollSizeUtils.cs @@ -0,0 +1,38 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace UnityEngine.UI +{ + public static class LoopScrollSizeUtils + { + public static float GetPreferredHeight(RectTransform item) + { + ILayoutElement minLayoutElement; + ILayoutElement preferredLayoutElement; + var minHeight = LayoutUtility.GetLayoutProperty(item, e => e.minHeight, 0, out minLayoutElement); + var preferredHeight = LayoutUtility.GetLayoutProperty(item, e => e.preferredHeight, 0, out preferredLayoutElement); + var result = Mathf.Max(minHeight, preferredHeight); + if (preferredLayoutElement == null && minLayoutElement == null) + { + result = item.rect.height; + } + + return result; + } + + public static float GetPreferredWidth(RectTransform item) + { + ILayoutElement minLayoutElement; + ILayoutElement preferredLayoutElement; + var minWidth = LayoutUtility.GetLayoutProperty(item, e => e.minWidth, 0, out minLayoutElement); + var preferredWidth = LayoutUtility.GetLayoutProperty(item, e => e.preferredWidth, 0, out preferredLayoutElement); + var result = Mathf.Max(minWidth, preferredWidth); + if (preferredLayoutElement == null && minLayoutElement == null) + { + result = item.rect.width; + } + + return result; + } + } +} \ No newline at end of file diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollSizeUtils.cs.meta b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollSizeUtils.cs.meta new file mode 100644 index 0000000..ccc2993 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopScrollSizeUtils.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e089162759fe4031997b918866745978 +timeCreated: 1721785991 \ No newline at end of file diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopVerticalScrollRect.cs b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopVerticalScrollRect.cs new file mode 100644 index 0000000..e35c9fb --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopVerticalScrollRect.cs @@ -0,0 +1,188 @@ +using UnityEngine; +using UnityEngine.UI; +using System.Collections; + +namespace UnityEngine.UI +{ + [AddComponentMenu("UI/Loop Vertical Scroll Rect", 51)] + [DisallowMultipleComponent] + public class LoopVerticalScrollRect : LoopScrollRect + { + protected LoopVerticalScrollRect() + { + direction = LoopScrollRectDirection.Vertical; + } + + protected override float GetSize(RectTransform item, bool includeSpacing) + { + float size = includeSpacing ? contentSpacing : 0; + if (m_GridLayout != null) + { + size += m_GridLayout.cellSize.y; + } + else + { + size += LoopScrollSizeUtils.GetPreferredHeight(item); + } + size *= m_Content.localScale.y; + return size; + } + + protected override float GetDimension(Vector2 vector) + { + return vector.y; + } + + protected override float GetAbsDimension(Vector2 vector) + { + return vector.y; + } + + protected override Vector2 GetVector(float value) + { + return new Vector2(0, value); + } + + protected override void Awake() + { + base.Awake(); + if (m_Content) + { + GridLayoutGroup layout = m_Content.GetComponent(); + if (layout != null && layout.constraint != GridLayoutGroup.Constraint.FixedColumnCount) + { + Debug.LogError("[LoopScrollRect] unsupported GridLayoutGroup constraint"); + } + } + } + + protected override bool UpdateItems(ref Bounds viewBounds, ref Bounds contentBounds) + { + bool changed = false; + + // special case: handling move several page in one frame + if ((viewBounds.size.y < contentBounds.min.y - viewBounds.max.y) && itemTypeEnd > itemTypeStart) + { + int maxItemTypeStart = -1; + if (totalCount >= 0) + { + maxItemTypeStart = Mathf.Max(0, totalCount - (itemTypeEnd - itemTypeStart)); + } + float currentSize = contentBounds.size.y; + float elementSize = EstimiateElementSize(); + ReturnToTempPool(true, itemTypeEnd - itemTypeStart); + itemTypeStart = itemTypeEnd; + + int offsetCount = Mathf.FloorToInt((contentBounds.min.y - viewBounds.max.y) / (elementSize + contentSpacing)); + if (maxItemTypeStart >= 0 && itemTypeStart + offsetCount * contentConstraintCount > maxItemTypeStart) + { + offsetCount = Mathf.FloorToInt((float)(maxItemTypeStart - itemTypeStart) / contentConstraintCount); + } + itemTypeStart += offsetCount * contentConstraintCount; + if (totalCount >= 0) + { + itemTypeStart = Mathf.Max(itemTypeStart, 0); + } + itemTypeEnd = itemTypeStart; + itemTypeSize = 0; + + float offset = offsetCount * (elementSize + contentSpacing); + m_Content.anchoredPosition -= new Vector2(0, offset + (reverseDirection ? 0 : currentSize)); + contentBounds.center -= new Vector3(0, offset + currentSize / 2, 0); + contentBounds.size = Vector3.zero; + + changed = true; + } + + if ((viewBounds.min.y - contentBounds.max.y > viewBounds.size.y) && itemTypeEnd > itemTypeStart) + { + float currentSize = contentBounds.size.y; + float elementSize = EstimiateElementSize(); + ReturnToTempPool(false, itemTypeEnd - itemTypeStart); + itemTypeEnd = itemTypeStart; + + int offsetCount = Mathf.FloorToInt((viewBounds.min.y - contentBounds.max.y) / (elementSize + contentSpacing)); + if (totalCount >= 0 && itemTypeStart - offsetCount * contentConstraintCount < 0) + { + offsetCount = Mathf.FloorToInt((float)(itemTypeStart) / contentConstraintCount); + } + itemTypeStart -= offsetCount * contentConstraintCount; + if (totalCount >= 0) + { + itemTypeStart = Mathf.Max(itemTypeStart, 0); + } + itemTypeEnd = itemTypeStart; + itemTypeSize = 0; + + float offset = offsetCount * (elementSize + contentSpacing); + m_Content.anchoredPosition += new Vector2(0, offset + (reverseDirection ? currentSize : 0)); + contentBounds.center += new Vector3(0, offset + currentSize / 2, 0); + contentBounds.size = Vector3.zero; + + changed = true; + } + // issue #149: new item before delete + if (viewBounds.min.y < contentBounds.min.y + m_ContentBottomPadding) + { + float size = NewItemAtEnd(), totalSize = size; + while (size > 0 && viewBounds.min.y < contentBounds.min.y + m_ContentBottomPadding - totalSize) + { + size = NewItemAtEnd(); + totalSize += size; + } + if (totalSize > 0) + changed = true; + } + // issue #178: grid layout could increase totalCount at any time + else if ((itemTypeEnd % contentConstraintCount != 0) && (itemTypeEnd < totalCount || totalCount < 0)) + { + NewItemAtEnd(); + } + + if (viewBounds.max.y > contentBounds.max.y - m_ContentTopPadding) + { + float size = NewItemAtStart(), totalSize = size; + while (size > 0 && viewBounds.max.y > contentBounds.max.y - m_ContentTopPadding + totalSize) + { + size = NewItemAtStart(); + totalSize += size; + } + if (totalSize > 0) + changed = true; + } + + if (viewBounds.min.y > contentBounds.min.y + threshold + m_ContentBottomPadding + && viewBounds.size.y < contentBounds.size.y - threshold) + { + float size = DeleteItemAtEnd(), totalSize = size; + while (size > 0 && viewBounds.min.y > contentBounds.min.y + threshold + m_ContentBottomPadding + totalSize) + { + size = DeleteItemAtEnd(); + totalSize += size; + } + if (totalSize > 0) + changed = true; + } + + if (viewBounds.max.y < contentBounds.max.y - threshold - m_ContentTopPadding + && viewBounds.size.y < contentBounds.size.y - threshold) + { + float size = DeleteItemAtStart(), totalSize = size; + while (size > 0 && viewBounds.max.y < contentBounds.max.y - threshold - m_ContentTopPadding - totalSize) + { + size = DeleteItemAtStart(); + totalSize += size; + } + if (totalSize > 0) + changed = true; + } + + if (changed) + { + ClearTempPool(); + } + + return changed; + } + } +} \ No newline at end of file diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopVerticalScrollRect.cs.meta b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopVerticalScrollRect.cs.meta new file mode 100644 index 0000000..b80e5d9 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopVerticalScrollRect.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ce71017a2903f7c4c9a699e438d0b897 +timeCreated: 1439395663 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopVerticalScrollRectMulti.cs b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopVerticalScrollRectMulti.cs new file mode 100644 index 0000000..e8e2615 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopVerticalScrollRectMulti.cs @@ -0,0 +1,187 @@ +using UnityEngine; +using UnityEngine.UI; +using System.Collections; + +namespace UnityEngine.UI +{ + [AddComponentMenu("UI/Loop Vertical Scroll Rect(MultiPrefab)", 53)] + [DisallowMultipleComponent] + public class LoopVerticalScrollRectMulti : LoopScrollRectMulti + { + protected LoopVerticalScrollRectMulti() + { + direction = LoopScrollRectDirection.Vertical; + } + + protected override float GetSize(RectTransform item, bool includeSpacing) + { + float size = includeSpacing ? contentSpacing : 0; + if (m_GridLayout != null) + { + size += m_GridLayout.cellSize.y; + } + else + { + size += LoopScrollSizeUtils.GetPreferredHeight(item); + } + size *= m_Content.localScale.y; + return size; + } + + protected override float GetDimension(Vector2 vector) + { + return vector.y; + } + + protected override float GetAbsDimension(Vector2 vector) + { + return vector.y; + } + + protected override Vector2 GetVector(float value) + { + return new Vector2(0, value); + } + + protected override void Awake() + { + base.Awake(); + if (m_Content) + { + GridLayoutGroup layout = m_Content.GetComponent(); + if (layout != null && layout.constraint != GridLayoutGroup.Constraint.FixedColumnCount) + { + Debug.LogError("[LoopScrollRect] unsupported GridLayoutGroup constraint"); + } + } + } + + protected override bool UpdateItems(ref Bounds viewBounds, ref Bounds contentBounds) + { + bool changed = false; + + // special case: handling move several page in one frame + if ((viewBounds.size.y < contentBounds.min.y - viewBounds.max.y) && itemTypeEnd > itemTypeStart) + { + int maxItemTypeStart = -1; + if (totalCount >= 0) + { + maxItemTypeStart = Mathf.Max(0, totalCount - (itemTypeEnd - itemTypeStart)); + } + float currentSize = contentBounds.size.y; + float elementSize = EstimiateElementSize(); + ReturnToTempPool(true, itemTypeEnd - itemTypeStart); + itemTypeStart = itemTypeEnd; + + int offsetCount = Mathf.FloorToInt((contentBounds.min.y - viewBounds.max.y) / (elementSize + contentSpacing)); + if (maxItemTypeStart >= 0 && itemTypeStart + offsetCount * contentConstraintCount > maxItemTypeStart) + { + offsetCount = Mathf.FloorToInt((float)(maxItemTypeStart - itemTypeStart) / contentConstraintCount); + } + itemTypeStart += offsetCount * contentConstraintCount; + if (totalCount >= 0) + { + itemTypeStart = Mathf.Max(itemTypeStart, 0); + } + itemTypeEnd = itemTypeStart; + itemTypeSize = 0; + + float offset = offsetCount * (elementSize + contentSpacing); + m_Content.anchoredPosition -= new Vector2(0, offset + (reverseDirection ? 0 : currentSize)); + contentBounds.center -= new Vector3(0, offset + currentSize / 2, 0); + contentBounds.size = Vector3.zero; + + changed = true; + } + + if ((viewBounds.min.y - contentBounds.max.y > viewBounds.size.y) && itemTypeEnd > itemTypeStart) + { + float currentSize = contentBounds.size.y; + float elementSize = EstimiateElementSize(); + ReturnToTempPool(false, itemTypeEnd - itemTypeStart); + itemTypeEnd = itemTypeStart; + + int offsetCount = Mathf.FloorToInt((viewBounds.min.y - contentBounds.max.y) / (elementSize + contentSpacing)); + if (totalCount >= 0 && itemTypeStart - offsetCount * contentConstraintCount < 0) + { + offsetCount = Mathf.FloorToInt((float)(itemTypeStart) / contentConstraintCount); + } + itemTypeStart -= offsetCount * contentConstraintCount; + if (totalCount >= 0) + { + itemTypeStart = Mathf.Max(itemTypeStart, 0); + } + itemTypeEnd = itemTypeStart; + itemTypeSize = 0; + + float offset = offsetCount * (elementSize + contentSpacing); + m_Content.anchoredPosition += new Vector2(0, offset + (reverseDirection ? currentSize : 0)); + contentBounds.center += new Vector3(0, offset + currentSize / 2, 0); + contentBounds.size = Vector3.zero; + + changed = true; + } + + if (viewBounds.min.y < contentBounds.min.y + m_ContentBottomPadding) + { + float size = NewItemAtEnd(), totalSize = size; + while (size > 0 && viewBounds.min.y < contentBounds.min.y + m_ContentBottomPadding - totalSize) + { + size = NewItemAtEnd(); + totalSize += size; + } + if (totalSize > 0) + changed = true; + } + else if ((itemTypeEnd % contentConstraintCount != 0) && (itemTypeEnd < totalCount || totalCount < 0)) + { + NewItemAtEnd(); + } + + if (viewBounds.max.y > contentBounds.max.y - m_ContentTopPadding) + { + float size = NewItemAtStart(), totalSize = size; + while (size > 0 && viewBounds.max.y > contentBounds.max.y - m_ContentTopPadding + totalSize) + { + size = NewItemAtStart(); + totalSize += size; + } + if (totalSize > 0) + changed = true; + } + + if (viewBounds.min.y > contentBounds.min.y + threshold + m_ContentBottomPadding + && viewBounds.size.y < contentBounds.size.y - threshold) + { + float size = DeleteItemAtEnd(), totalSize = size; + while (size > 0 && viewBounds.min.y > contentBounds.min.y + threshold + m_ContentBottomPadding + totalSize) + { + size = DeleteItemAtEnd(); + totalSize += size; + } + if (totalSize > 0) + changed = true; + } + + if (viewBounds.max.y < contentBounds.max.y - threshold - m_ContentTopPadding + && viewBounds.size.y < contentBounds.size.y - threshold) + { + float size = DeleteItemAtStart(), totalSize = size; + while (size > 0 && viewBounds.max.y < contentBounds.max.y - threshold - m_ContentTopPadding - totalSize) + { + size = DeleteItemAtStart(); + totalSize += size; + } + if (totalSize > 0) + changed = true; + } + + if (changed) + { + ClearTempPool(); + } + + return changed; + } + } +} \ No newline at end of file diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopVerticalScrollRectMulti.cs.meta b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopVerticalScrollRectMulti.cs.meta new file mode 100644 index 0000000..7ee8b9f --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/Runtime/LoopVerticalScrollRectMulti.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a4ae502f584e1924d83adb15f18817dc +timeCreated: 1439395663 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/UILoopList.cs b/UnityGame/Assets/Scripts/ThirdParty/LoopList/UILoopList.cs new file mode 100644 index 0000000..44fc471 --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/UILoopList.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +namespace CreatGame.UI +{ + /// + /// item提供者 + /// + public delegate string LoopListItemProvider(int index); + /// + /// item渲染函数 + /// + public delegate void LoopListItemRenderer(GameObject item,int index); + public class UILoopList : MonoBehaviour, LoopScrollPrefabSource, LoopScrollDataSource + { + /// + /// + /// + public LoopListItemProvider ListItemProvider; + /// + /// + /// + public LoopListItemRenderer ListItemRenderer; + /// + /// + /// + private Dictionary> itemPool = new Dictionary>(); + /// + /// 预制件 + /// + public GameObject itemPrefab; + public GameObject GetObject(int index) + { + string itemPath = String.Empty; + if (ListItemProvider != null) + { + itemPath = ListItemProvider(index); + } + else + { + itemPath = "Default"; + } + + if (itemPool.TryGetValue(itemPath, out Stack itemList) == false) + { + itemList = new Stack(); + itemPool.Add(itemPath, itemList); + } + + if (itemList.Count == 0) + { + if (ListItemProvider == null) + { + if (itemPrefab != null) + { + itemList.Push(Instantiate(itemPrefab)); + } + else + { + Debug.LogError("ItemPrefab is null and ListItemProvider == null"); + return null; + } + } + else + { + var item = AssetBundle.AssetBundleManager.Instance.LoadGameObject(itemPath); + var export = item.GetComponent(); + if (export == null) + { + Debug.LogError("预制件没有绑定导出代码的UIViewBase"); + } + + export.PreLoad(item); + itemList.Push(item); + } + } + + return itemList.Pop(); + } + + public void ReturnObject(Transform trans) + { + var export = trans.GetComponent(); + if (export != null) + { + if (itemPool.TryGetValue(export.PrefabPath, out Stack itemList) ==false) + { + itemList = itemPool["Default"]; + } + + itemList.Push(trans.gameObject); + } + else + { + Debug.LogError("返回对象池失败"); + } + } + + public void ProvideData(Transform transform, int idx) + { + if (ListItemRenderer == null) + { + Debug.LogError("ListItemRenderer is null"); + return; + } + ListItemRenderer(transform.gameObject, idx); + } + + /// + /// + /// + public LoopScrollRect ScrollRect { get; private set; } + + private void Start() + { + ScrollRect = GetComponent(); + ScrollRect.prefabSource = this; + ScrollRect.dataSource = this; + } + + public int ItemCount + { + get => ScrollRect.totalCount; + set => ScrollRect.totalCount = value; + } + + public void RefillCells() + { + ScrollRect?.RefillCells(); + } + + } +} \ No newline at end of file diff --git a/UnityGame/Assets/Scripts/ThirdParty/LoopList/UILoopList.cs.meta b/UnityGame/Assets/Scripts/ThirdParty/LoopList/UILoopList.cs.meta new file mode 100644 index 0000000..0acfc4c --- /dev/null +++ b/UnityGame/Assets/Scripts/ThirdParty/LoopList/UILoopList.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7147f1d79bae489b95b90268646bc8bf +timeCreated: 1752913702 \ No newline at end of file diff --git a/UnityGame/UserSettings/Layouts/default-2022.dwlt b/UnityGame/UserSettings/Layouts/default-2022.dwlt index e68477f..b4645f4 100644 --- a/UnityGame/UserSettings/Layouts/default-2022.dwlt +++ b/UnityGame/UserSettings/Layouts/default-2022.dwlt @@ -19,7 +19,7 @@ MonoBehaviour: width: 2048 height: 1060.8 m_ShowMode: 4 - m_Title: Console + m_Title: Project m_RootView: {fileID: 7} m_MinSize: {x: 875, y: 300} m_MaxSize: {x: 10000, y: 10000} @@ -74,7 +74,7 @@ MonoBehaviour: m_MinSize: {x: 200, y: 50} m_MaxSize: {x: 16192, y: 8096} vertical: 0 - controlID: 54 + controlID: 92 draggingID: 0 --- !u!114 &4 MonoBehaviour: @@ -126,7 +126,7 @@ MonoBehaviour: m_MinSize: {x: 300, y: 100} m_MaxSize: {x: 24288, y: 16192} vertical: 1 - controlID: 16 + controlID: 91 draggingID: 0 --- !u!114 &6 MonoBehaviour: @@ -229,7 +229,7 @@ MonoBehaviour: m_MinSize: {x: 300, y: 50} m_MaxSize: {x: 24288, y: 8096} vertical: 0 - controlID: 17 + controlID: 38 draggingID: 0 --- !u!114 &10 MonoBehaviour: @@ -271,8 +271,8 @@ MonoBehaviour: y: 0 width: 590.4 height: 652 - m_MinSize: {x: 275, y: 50} - m_MaxSize: {x: 4000, y: 4000} + m_MinSize: {x: 276, y: 71} + m_MaxSize: {x: 4001, y: 4021} m_ActualView: {fileID: 15} m_Panes: - {fileID: 15} @@ -376,9 +376,9 @@ MonoBehaviour: m_SceneHierarchy: m_TreeViewState: scrollPos: {x: 0, y: 0} - m_SelectedIDs: 90600000 + m_SelectedIDs: 0a5f0000 m_LastClickedID: 0 - m_ExpandedIDs: 6af4ffff76f4ffff9c6000009e600000 + m_ExpandedIDs: 0cfaffff m_RenameOverlay: m_UserAcceptedRename: 0 m_Name: @@ -494,7 +494,7 @@ MonoBehaviour: m_SkipHidden: 0 m_SearchArea: 1 m_Folders: - - Assets/AssetBundle/Config + - Assets/Scripts/ThirdParty/LoopList/Runtime m_Globs: [] m_OriginalText: m_ImportLogFlags: 0 @@ -510,7 +510,7 @@ MonoBehaviour: scrollPos: {x: 0, y: 0} m_SelectedIDs: b2df0000 m_LastClickedID: 57266 - m_ExpandedIDs: 00000000985f00009a5f00009c5f00009e5f0000a05f0000a25f0000a45f0000a65f0000a85f0000aa5f0000ac5f0000ae5f0000b05f0000 + m_ExpandedIDs: 00000000fc5f0000fe5f000000600000026000000460000006600000086000000a6000000c6000000e6000001060000012600000146000001660000018600000 m_RenameOverlay: m_UserAcceptedRename: 0 m_Name: @@ -535,10 +535,10 @@ MonoBehaviour: m_Icon: {fileID: 0} m_ResourceFile: m_AssetTreeState: - scrollPos: {x: 0, y: 0} + scrollPos: {x: 0, y: 172.19995} m_SelectedIDs: m_LastClickedID: 0 - m_ExpandedIDs: ffffffff00000000985f00009a5f00009c5f00009e5f0000a05f0000a25f0000a45f0000a65f0000a85f0000aa5f0000ac5f0000ae5f0000b05f0000da5f0000e45f0000 + m_ExpandedIDs: ffffffff00000000ca5e0000d25e0000fc5f0000fe5f00000260000004600000066000000c6000000e60000054600000 m_RenameOverlay: m_UserAcceptedRename: 0 m_Name: @@ -770,7 +770,7 @@ MonoBehaviour: collapsed: 0 displayed: 0 snapOffset: {x: 0, y: 0} - snapOffsetDelta: {x: 0, y: 24.8} + snapOffsetDelta: {x: 0, y: 0} snapCorner: 1 id: unity-search-toolbar index: 1 @@ -822,7 +822,7 @@ MonoBehaviour: collapsed: 0 displayed: 0 snapOffset: {x: 0, y: 0} - snapOffsetDelta: {x: 0, y: 24.8} + snapOffsetDelta: {x: 0, y: 0} snapCorner: 0 id: Scene View/Light Settings index: 0 @@ -848,7 +848,7 @@ MonoBehaviour: collapsed: 0 displayed: 0 snapOffset: {x: 0, y: 0} - snapOffsetDelta: {x: 0, y: 24.8} + snapOffsetDelta: {x: 0, y: 0} snapCorner: 0 id: Scene View/Cloth Constraints index: 1 @@ -861,7 +861,7 @@ MonoBehaviour: collapsed: 0 displayed: 0 snapOffset: {x: 0, y: 0} - snapOffsetDelta: {x: 0, y: 24.8} + snapOffsetDelta: {x: 0, y: 0} snapCorner: 0 id: Scene View/Cloth Collisions index: 2 @@ -913,7 +913,7 @@ MonoBehaviour: collapsed: 0 displayed: 0 snapOffset: {x: 0, y: 0} - snapOffsetDelta: {x: 0, y: 24.8} + snapOffsetDelta: {x: 0, y: 0} snapCorner: 0 id: Scene View/Occlusion Culling index: 3 @@ -926,7 +926,7 @@ MonoBehaviour: collapsed: 0 displayed: 0 snapOffset: {x: 0, y: 0} - snapOffsetDelta: {x: 0, y: 24.8} + snapOffsetDelta: {x: 0, y: 0} snapCorner: 0 id: Scene View/Physics Debugger index: 4 @@ -939,7 +939,7 @@ MonoBehaviour: collapsed: 0 displayed: 0 snapOffset: {x: 0, y: 0} - snapOffsetDelta: {x: 0, y: 24.8} + snapOffsetDelta: {x: 0, y: 0} snapCorner: 0 id: Scene View/Scene Visibility index: 5 @@ -952,7 +952,7 @@ MonoBehaviour: collapsed: 0 displayed: 0 snapOffset: {x: 0, y: 0} - snapOffsetDelta: {x: 0, y: 24.8} + snapOffsetDelta: {x: 0, y: 0} snapCorner: 0 id: Scene View/Particles index: 6 @@ -1053,15 +1053,15 @@ MonoBehaviour: m_OverlaysVisible: 1 m_WindowGUID: 4b0f6f5c8c62bf3488500418d3d8472c m_Gizmos: 1 - m_OverrideSceneCullingMask: 0 - m_SceneIsLit: 0 + m_OverrideSceneCullingMask: 6917529027641081856 + m_SceneIsLit: 1 m_SceneLighting: 1 - m_2DMode: 1 + m_2DMode: 0 m_isRotationLocked: 0 m_PlayAudio: 0 m_AudioPlay: 0 m_Position: - m_Target: {x: 555.8997, y: 291.5927, z: -0.53083503} + m_Target: {x: -3.6708412, y: -4.282875, z: 44.11006} speed: 2 m_Value: {x: 555.8997, y: 291.5927, z: -0.53083503} m_RenderMode: 0 @@ -1074,7 +1074,7 @@ MonoBehaviour: m_SceneViewState: m_AlwaysRefresh: 0 showFog: 1 - showSkybox: 0 + showSkybox: 1 showFlares: 1 showImageEffects: 1 showParticleSystems: 1 @@ -1091,15 +1091,15 @@ MonoBehaviour: m_Size: {x: 0, y: 0} yGrid: m_Fade: - m_Target: 0 + m_Target: 1 speed: 2 - m_Value: 0 + m_Value: 1 m_Color: {r: 0.5, g: 0.5, b: 0.5, a: 0.4} m_Pivot: {x: 0, y: 0, z: 0} m_Size: {x: 1, y: 1} zGrid: m_Fade: - m_Target: 1 + m_Target: 0 speed: 2 m_Value: 1 m_Color: {r: 0.5, g: 0.5, b: 0.5, a: 0.4} @@ -1109,17 +1109,17 @@ MonoBehaviour: m_GridAxis: 1 m_gridOpacity: 0.5 m_Rotation: - m_Target: {x: 0, y: 0, z: 0, w: 1} + m_Target: {x: -0.25270963, y: 0.65854186, z: -0.25104713, w: -0.6629036} speed: 2 m_Value: {x: 0, y: 0, z: 0, w: 1} m_Size: - m_Target: 522.41943 + m_Target: 53.034447 speed: 2 m_Value: 522.41943 m_Ortho: - m_Target: 1 + m_Target: 0 speed: 2 - m_Value: 1 + m_Value: 0 m_CameraSettings: m_Speed: 1 m_SpeedNormalized: 0.5 @@ -1133,7 +1133,7 @@ MonoBehaviour: m_FarClip: 10000 m_DynamicClip: 1 m_OcclusionCulling: 0 - m_LastSceneViewRotation: {x: -0.25270963, y: 0.65854186, z: -0.25104713, w: -0.6629036} + m_LastSceneViewRotation: {x: -0.08717229, y: 0.89959055, z: -0.21045254, w: -0.3726226} m_LastSceneViewOrtho: 0 m_ReplacementShader: {fileID: 0} m_ReplacementString: