diff --git a/README.md b/README.md index f71943a..1a2d380 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,10 @@ To get started with the project, here's a little guide: [![View Getting Started Video](http://img.youtube.com/vi/sVLeYmsNQAI/0.jpg)](http://www.youtube.com/watch?v=sVLeYmsNQAI "Unity UI getting started video") --- - +## Updates: ## +Update 1.0.0.4 +[![View Getting Started Video](http://img.youtube.com/vi/oF48Qpaq3ls/0.jpg)](http://www.youtube.com/watch?v=oF48Qpaq3ls "Update 1.0.0.4 for the Unity UI Extensions Project") +--- ## Controls and extensions listed in this project are: ## ## Controls ## @@ -54,9 +57,9 @@ Control | Description | Menu Command | Component Command | Notes | Credits --------- | -------------- | ---------------------- | ---------------------------- | ------- | ---------- **LineRenderer** | Graphic control for drawing lines in the UI System | UI / Extensions / Primitives / UI Line Renderer | UI / Extensions / Primitives / UI Line Renderer |[tutorial video](https://www.youtube.com/watch?v=OElcWAZGHi0)| jack.sydorenko **UILineTextureRenderer** | Graphic control for drawing lines in the UI System | UI / Extensions / Primitives / UI Line Texture Renderer | UI / Extensions / Primitives / UI Line Texture Renderer |[tutorial video](https://www.youtube.com/watch?v=OElcWAZGHi0)| jack.sydorenko, jonbro5556 -**UICircle** | Graphic control for drawing circles in the UI System | UI / Extensions / Primitives / UI Circle | UI / Extensions / Primitives / UI Circle || zge -**DiamondGraph** | Graphic control for drawing a diamond in the UI System | UI / Extensions / Primitives / DiamondGraph | UI / Extensions / Primitives / DiamondGraph |5.2+ only| koohddang - +**UICircle** | Graphic control for drawing circles in the UI System | UI / Extensions / Primitives / UI Circle | UI / Extensions / Primitives / UI Circle |[tutorial video](https://www.youtube.com/watch?v=2KOnEKAVua0)| zge +**DiamondGraph** | Graphic control for drawing a diamond in the UI System | UI / Extensions / Primitives / DiamondGraph | UI / Extensions / Primitives / DiamondGraph |5.2+ only [tutorial video](https://www.youtube.com/watch?v=2KOnEKAVua0)| koohddang +**UICornerCut** | Graphic control for drawing a diamond in the UI System | UI/Extensions/Primitives/Cut Corners | UI/Extensions/Primitives/Cut Corners || Freezy ## Layouts ## @@ -67,9 +70,12 @@ Layout | Description | Menu Command | Component Command | Notes | Credits **HorizontalScrollSnap** | A pages scroll rect that can work in steps / pages, includes button support | UI / Extensions / Horizontal Scroll Snap | Layout / Extensions / Horizontal Scroll Snap |[tutorial video](https://www.youtube.com/watch?v=KJlIlWHlfMo)| BinaryX **VerticalScrollSnap** | A pages scroll rect that can work in steps / pages, includes button support | UI / Extensions / Vertical Scroll Snap | Layout / Extensions / Vertical Scroll Snap |[tutorial video](https://www.youtube.com/watch?v=KJlIlWHlfMo)| BinaryX, Simon Darkside Jackson **FlowLayoutGroup** | A more rugged grid style layout group || Layout / Extensions / Flow Layout Group | [Example Video](https://www.youtube.com/watch?v=tMe_3tJTZvc) | Simie -**RadialLayout** | A radial layout system || Layout / Extensions / Radial Layout || Danny Goodayle -**TileSizeFitter** | A fitter layout that will shink / expand content by tiles || Layout / Extensions / TileSizeFitter || Ges - +**RadialLayout** | A radial layout system || Layout / Extensions / Radial Layout |[tutorial video](https://www.youtube.com/watch?v=iUlk0d2RDMs)| Danny Goodayle +**TileSizeFitter** | A fitter layout that will shink / expand content by tiles || Layout / Extensions / TileSizeFitter |[tutorial video](https://www.youtube.com/watch?v=AkQNWl8mnxg)| Ges +**ScrollSnap** | An alternate scroll snap control supporting both Horizontal and Vertial layous in one control | UI / Extensions / Fixed Item Scroll / Snap Horizontal Single Item||| xesenix +|| UI / Extensions / Fixed Item Scroll / Snap Horizontal Multiple Item||| xesenix +|| UI / Extensions / Fixed Item Scroll / Snap Vertical Single Item||| xesenix +|| UI / Extensions / Fixed Item Scroll / Snap Vertical Multiple Item||| xesenix ## Effect components ## @@ -85,6 +91,7 @@ Effect | Description | Component Command | Notes | Credits **RaycastMask** | An example of an enhanced mask component able to work with the image data. Enables picking on image parts and not just the Rect Transform | UI / Effects / Extensions / Raycast Mask | | senritsu **UIFlippable** | Image component effect to flip the graphic | UI / Effects / Extensions / UI Flippable | | ChoMPHi + ## VR Components## ======================= @@ -94,6 +101,14 @@ Component | Description | Component Command | Notes | Credits **VRInputModule** | Input module to support the VR Cursor | Event / Vr Input Module | | Ralph Barbagallo +## Input Modules ## +======================= + +Component | Description | Component Command | Notes | Credits +--------- | -------------- | ---------------------------- | ------- | ------ +**AimerInputModule** | Replacement Input module to allow for a reciclue to interace with WorldSpace canvas UI | Event / Extensions / Aimer Input Module | | Chris Trueman +**GamePadInputModule** | Stripped down SIM Input module for just gamepad/keybord input | Event / Extensions / GamePad Input Module | | Simon (darkside) Jackson + ## Additional Components## ======================= @@ -108,7 +123,6 @@ Component | Description | Component Command | Notes | Credits **InputFocus** | Enhanced InputField control for forms, enables Enter to submit and other features | UI / Extensions / InputFocus | | Zelek **ImageExtended** | Improved Image control with rotation support and use of filled type without an Image (useful for masks) | UI / Extensions / Image Extended | | Ges **UIScrollToSelection** | Enables a ScrollRect to scroll based on the selected child automatically | UI / Extensions / UIScrollToSelection | | zero3growlithe -**AimerInputModule** | Replacement Input module to allow for a reciclue to interace with WorldSpace canvas UI | UI / Extensions / Aimer Input Module | | Chris Trueman **UISelectableExtension** | Refactor of original UI Button control, can now add Press/Release and Hold events to any Selectable control | UI / Extensions / UI Selectable Extension | | AriathTheWise / Simon Jackson **switchToRectTransform** | RectTransform extension method to move one Rect to another | N/A | | Izitmee diff --git a/Scripts/Editor/UIExtensionsMenuOptions.cs b/Scripts/Editor/UIExtensionsMenuOptions.cs index 0c4ebba..7d2cf5e 100644 --- a/Scripts/Editor/UIExtensionsMenuOptions.cs +++ b/Scripts/Editor/UIExtensionsMenuOptions.cs @@ -897,6 +897,14 @@ namespace UnityEditor.UI go.AddComponent(); Selection.activeGameObject = go; } + + [MenuItem("GameObject/UI/Extensions/Primitives/Cut Corners", false)] + static public void AddCutCorners(MenuCommand menuCommand) + { + GameObject go = CreateUIElementRoot("Cut Corners", menuCommand, s_ImageGUIElementSize); + go.AddComponent(); + Selection.activeGameObject = go; + } #endregion @@ -1032,5 +1040,268 @@ namespace UnityEditor.UI } #endregion + + #region New ScrollSnapCode + static public void FixedScrollSnapBase(MenuCommand menuCommand, string name, ScrollSnap.ScrollDirection direction, int itemVisible, int itemCount, Vector2 itemSize) + + { + + GameObject scrollSnapRoot = CreateUIElementRoot(name, menuCommand, s_ThickGUIElementSize); + + + + GameObject itemList = CreateUIObject("List", scrollSnapRoot); + + + + // Set RectTransform to stretch + + RectTransform rectTransformScrollSnapRoot = scrollSnapRoot.GetComponent(); + + rectTransformScrollSnapRoot.anchorMin = new Vector2(0.5f, 0.5f); + + rectTransformScrollSnapRoot.anchorMax = new Vector2(0.5f, 0.5f); + + rectTransformScrollSnapRoot.anchoredPosition = Vector2.zero; + + + + if (direction == ScrollSnap.ScrollDirection.Horizontal) + + { + + rectTransformScrollSnapRoot.sizeDelta = new Vector2(itemVisible * itemSize.x, itemSize.y); + + } + + else + + { + + rectTransformScrollSnapRoot.sizeDelta = new Vector2(itemSize.x, itemVisible * itemSize.y); + + } + + + + Image image = scrollSnapRoot.AddComponent(); + + image.sprite = AssetDatabase.GetBuiltinExtraResource(kBackgroundSpriteResourcePath); + + image.type = Image.Type.Sliced; + + image.color = new Color(1f, 1f, 1f, 1f); + + + + Mask listMask = scrollSnapRoot.AddComponent(); + + listMask.showMaskGraphic = false; + + + + ScrollRect scrollRect = scrollSnapRoot.AddComponent(); + + scrollRect.vertical = direction == ScrollSnap.ScrollDirection.Vertical; + + scrollRect.horizontal = direction == ScrollSnap.ScrollDirection.Horizontal; + + + + ScrollSnap scrollSnap = scrollSnapRoot.AddComponent(); + + scrollSnap.direction = direction; + + scrollSnap.itemsVisibleAtOnce = itemVisible; + + + + //Setup Content container + + RectTransform rectTransformContent = itemList.GetComponent(); + + rectTransformContent.anchorMin = Vector2.zero; + + rectTransformContent.anchorMax = new Vector2(1f, 1f); + + //rectTransformContent.anchoredPosition = Vector2.zero; + + rectTransformContent.sizeDelta = Vector2.zero; + + scrollRect.content = rectTransformContent; + + + + //Setup Item list container + + if (direction == ScrollSnap.ScrollDirection.Horizontal) + + { + + itemList.AddComponent (); + + ContentSizeFitter sizeFitter = itemList.AddComponent(); + + sizeFitter.horizontalFit = ContentSizeFitter.FitMode.MinSize; + + } + + else + + { + + itemList.AddComponent (); + + ContentSizeFitter sizeFitter = itemList.AddComponent(); + + sizeFitter.verticalFit = ContentSizeFitter.FitMode.MinSize; + + } + + + + //Setup children + + + + for (var i = 0; i < itemCount; i ++) + + { + + GameObject item = CreateUIObject (string.Format("Item_{0:00}", i), itemList); + + + + GameObject childText = CreateUIObject ("Text", item); + + + + Image pageImage = item.AddComponent (); + + pageImage.sprite = AssetDatabase.GetBuiltinExtraResource (kStandardSpritePath); + + pageImage.type = Image.Type.Sliced; + + pageImage.color = s_DefaultSelectableColor; + + + + LayoutElement elementLayout = item.AddComponent (); + + if (direction == ScrollSnap.ScrollDirection.Horizontal) + + { + + elementLayout.minWidth = itemSize.x; + + } + + else + + { + + elementLayout.minHeight = itemSize.y; + + } + + + + RectTransform rectTransformPage01 = item.GetComponent (); + + rectTransformPage01.anchorMin = new Vector2 (0f, 0.5f); + + rectTransformPage01.anchorMax = new Vector2 (0f, 0.5f); + + //rectTransformPage01.anchoredPosition = Vector2.zero; + + //rectTransformPage01.sizeDelta = Vector2.zero; + + rectTransformPage01.pivot = new Vector2 (0f, 0.5f); + + + + //Setup Text on Page01 + + Text text = childText.AddComponent (); + + text.text = item.name; + + text.alignment = TextAnchor.MiddleCenter; + + text.color = new Color (0.196f, 0.196f, 0.196f); + + + + //Setup Text 1st Child + + RectTransform rectTransformPage01Text = childText.GetComponent (); + + rectTransformPage01Text.anchorMin = new Vector2 (0.5f, 0.5f); + + rectTransformPage01Text.anchorMax = new Vector2 (0.5f, 0.5f); + + //rectTransformPage01Text.anchoredPosition = Vector2.zero; + + //rectTransformPage01Text.sizeDelta = Vector2.zero; + + rectTransformPage01Text.pivot = new Vector2 (0.5f, 0.5f); + + } + + + + Selection.activeGameObject = scrollSnapRoot; + + } + + + + [MenuItem("GameObject/UI/Extensions/Fixed Item Scroll/Snap Horizontal Single Item", false)] + + static public void AddFixedItemScrollSnapHorizontalSingle(MenuCommand menuCommand) + + { + + FixedScrollSnapBase (menuCommand, "Scroll Snap Horizontal Single", ScrollSnap.ScrollDirection.Horizontal, 1, 3, new Vector2(100, 100)); + + } + + + + [MenuItem("GameObject/UI/Extensions/Fixed Item Scroll/Snap Horizontal Multiple Items", false)] + + static public void AddFixedItemScrollSnapHorizontalMultiple(MenuCommand menuCommand) + + { + + FixedScrollSnapBase (menuCommand, "Scroll Snap Horizontal Multiple", ScrollSnap.ScrollDirection.Horizontal, 3, 15, new Vector2(100, 100)); + + } + + + + [MenuItem("GameObject/UI/Extensions/Fixed Item Scroll/Snap Vertical Single Item", false)] + + static public void AddFixedItemScrollSnapVerticalSingle(MenuCommand menuCommand) + + { + + FixedScrollSnapBase (menuCommand, "Scroll Snap Vertical Multiple", ScrollSnap.ScrollDirection.Vertical, 1, 3, new Vector2(100, 100)); + + } + + + + [MenuItem("GameObject/UI/Extensions/Fixed Item Scroll/Snap Vertical Multiple Items", false)] + + static public void AddFixedItemScrollSnapVerticalMultiple(MenuCommand menuCommand) + + { + + FixedScrollSnapBase (menuCommand, "Scroll Snap Vertical Multiple", ScrollSnap.ScrollDirection.Vertical, 3, 15, new Vector2(100, 100)); + + } + + #endregion } } diff --git a/Scripts/HSVPicker/HexRGB.cs b/Scripts/HSVPicker/HexRGB.cs index c63ba66..0c3ba70 100644 --- a/Scripts/HSVPicker/HexRGB.cs +++ b/Scripts/HSVPicker/HexRGB.cs @@ -7,7 +7,8 @@ namespace UnityEngine.UI.Extensions { public class HexRGB : MonoBehaviour { - public Text textColor; + // Unity 5.1/2 needs an InputFiled vs grabbing the text component + public InputField hexInput; public HSVPicker hsvpicker; @@ -15,7 +16,7 @@ namespace UnityEngine.UI.Extensions { Color color = hsvpicker.currentColor; string hex = ColorToHex(color); - textColor.text = hex; + hexInput.text = hex; } public static string ColorToHex(Color color) @@ -28,8 +29,7 @@ namespace UnityEngine.UI.Extensions public void ManipulateViaHex2RGB() { - string hex = textColor.text; - + string hex = hexInput.text; Vector3 rgb = Hex2RGB(hex); Color color = NormalizeVector4(rgb, 255f, 1f); print(rgb); diff --git a/Scripts/InputModules.meta b/Scripts/InputModules.meta new file mode 100644 index 0000000..2969fc2 --- /dev/null +++ b/Scripts/InputModules.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: a0789c2f62bad6b4c800a3dc502fa18e +folderAsset: yes +DefaultImporter: + userData: diff --git a/Scripts/AimerInputModule.cs b/Scripts/InputModules/AimerInputModule.cs similarity index 96% rename from Scripts/AimerInputModule.cs rename to Scripts/InputModules/AimerInputModule.cs index 2f00b8a..199b656 100644 --- a/Scripts/AimerInputModule.cs +++ b/Scripts/InputModules/AimerInputModule.cs @@ -4,7 +4,7 @@ namespace UnityEngine.EventSystems.Extensions { [RequireComponent(typeof(EventSystem))] - [AddComponentMenu("UI/Extensions/Aimer Input Module")] + [AddComponentMenu("Event/Extensions/Aimer Input Module")] public class AimerInputModule : PointerInputModule { /// diff --git a/Scripts/AimerInputModule.cs.meta b/Scripts/InputModules/AimerInputModule.cs.meta similarity index 78% rename from Scripts/AimerInputModule.cs.meta rename to Scripts/InputModules/AimerInputModule.cs.meta index 9a98d82..ee7993f 100644 --- a/Scripts/AimerInputModule.cs.meta +++ b/Scripts/InputModules/AimerInputModule.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f7d3d69aa5226dc4493464d3b5e4ddc3 +guid: 08b9f423b73fdfb47b59e7de89863600 MonoImporter: serializedVersion: 2 defaultReferences: [] diff --git a/Scripts/InputModules/GamePadInputModule.cs b/Scripts/InputModules/GamePadInputModule.cs new file mode 100644 index 0000000..5e9d89e --- /dev/null +++ b/Scripts/InputModules/GamePadInputModule.cs @@ -0,0 +1,226 @@ +/// Credit Simon (darkside) Jackson +/// Sourced from - UI SIM source and My Brain + +namespace UnityEngine.EventSystems +{ + [AddComponentMenu("Event/Extensions/GamePad Input Module")] + public class GamePadInputModule : BaseInputModule + { + private float m_PrevActionTime; + Vector2 m_LastMoveVector; + int m_ConsecutiveMoveCount = 0; + + protected GamePadInputModule() + {} + + [SerializeField] + private string m_HorizontalAxis = "Horizontal"; + + /// + /// Name of the vertical axis for movement (if axis events are used). + /// + [SerializeField] + private string m_VerticalAxis = "Vertical"; + + /// + /// Name of the submit button. + /// + [SerializeField] + private string m_SubmitButton = "Submit"; + + /// + /// Name of the submit button. + /// + [SerializeField] + private string m_CancelButton = "Cancel"; + + [SerializeField] + private float m_InputActionsPerSecond = 10; + + [SerializeField] + private float m_RepeatDelay = 0.1f; + + public float inputActionsPerSecond + { + get { return m_InputActionsPerSecond; } + set { m_InputActionsPerSecond = value; } + } + + public float repeatDelay + { + get { return m_RepeatDelay; } + set { m_RepeatDelay = value; } + } + + /// + /// Name of the horizontal axis for movement (if axis events are used). + /// + public string horizontalAxis + { + get { return m_HorizontalAxis; } + set { m_HorizontalAxis = value; } + } + + /// + /// Name of the vertical axis for movement (if axis events are used). + /// + public string verticalAxis + { + get { return m_VerticalAxis; } + set { m_VerticalAxis = value; } + } + + public string submitButton + { + get { return m_SubmitButton; } + set { m_SubmitButton = value; } + } + + public string cancelButton + { + get { return m_CancelButton; } + set { m_CancelButton = value; } + } + + public override bool ShouldActivateModule() + { + if (!base.ShouldActivateModule()) + return false; + + var shouldActivate = true; + shouldActivate |= Input.GetButtonDown(m_SubmitButton); + shouldActivate |= Input.GetButtonDown(m_CancelButton); + shouldActivate |= !Mathf.Approximately(Input.GetAxisRaw(m_HorizontalAxis), 0.0f); + shouldActivate |= !Mathf.Approximately(Input.GetAxisRaw(m_VerticalAxis), 0.0f); + return shouldActivate; + } + + public override void ActivateModule() + { + StandaloneInputModule StandAloneSystem = GetComponent(); + + if (StandAloneSystem && StandAloneSystem.enabled) + { + Debug.LogError("StandAloneInputSystem should not be used with the GamePadInputModule, " + + "please remove it from the Event System in this scene or disable it when this module is in use"); + } + + base.ActivateModule(); + + var toSelect = eventSystem.currentSelectedGameObject; + if (toSelect == null) + toSelect = eventSystem.firstSelectedGameObject; + + eventSystem.SetSelectedGameObject(toSelect, GetBaseEventData()); + } + + public override void DeactivateModule() + { + base.DeactivateModule(); + } + + public override void Process() + { + bool usedEvent = SendUpdateEventToSelectedObject(); + + if (eventSystem.sendNavigationEvents) + { + if (!usedEvent) + usedEvent |= SendMoveEventToSelectedObject(); + + if (!usedEvent) + SendSubmitEventToSelectedObject(); + } + } + + /// + /// Process submit keys. + /// + protected bool SendSubmitEventToSelectedObject() + { + if (eventSystem.currentSelectedGameObject == null) + return false; + + var data = GetBaseEventData(); + if (Input.GetButtonDown(m_SubmitButton)) + ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.submitHandler); + + if (Input.GetButtonDown(m_CancelButton)) + ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.cancelHandler); + return data.used; + } + + private Vector2 GetRawMoveVector() + { + Vector2 move = Vector2.zero; + move.x = Input.GetAxisRaw(m_HorizontalAxis); + move.y = Input.GetAxisRaw(m_VerticalAxis); + + if (Input.GetButtonDown(m_HorizontalAxis)) + { + if (move.x < 0) + move.x = -1f; + if (move.x > 0) + move.x = 1f; + } + if (Input.GetButtonDown(m_VerticalAxis)) + { + if (move.y < 0) + move.y = -1f; + if (move.y > 0) + move.y = 1f; + } + return move; + } + + /// + /// Process events. + /// + protected bool SendMoveEventToSelectedObject() + { + float time = Time.unscaledTime; + + Vector2 movement = GetRawMoveVector(); + if (Mathf.Approximately(movement.x, 0f) && Mathf.Approximately(movement.y, 0f)) + { + m_ConsecutiveMoveCount = 0; + return false; + } + + // If user pressed key again, always allow event + bool allow = Input.GetButtonDown(m_HorizontalAxis) || Input.GetButtonDown(m_VerticalAxis); + bool similarDir = (Vector2.Dot(movement, m_LastMoveVector) > 0); + if (!allow) + { + // Otherwise, user held down key or axis. + // If direction didn't change at least 90 degrees, wait for delay before allowing consequtive event. + if (similarDir && m_ConsecutiveMoveCount == 1) + allow = (time > m_PrevActionTime + m_RepeatDelay); + // If direction changed at least 90 degree, or we already had the delay, repeat at repeat rate. + else + allow = (time > m_PrevActionTime + 1f / m_InputActionsPerSecond); + } + if (!allow) + return false; + + var axisEventData = GetAxisEventData(movement.x, movement.y, 0.6f); + ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, axisEventData, ExecuteEvents.moveHandler); + if (!similarDir) + m_ConsecutiveMoveCount = 0; + m_ConsecutiveMoveCount++; + m_PrevActionTime = time; + m_LastMoveVector = movement; + return axisEventData.used; + } + + protected bool SendUpdateEventToSelectedObject() + { + if (eventSystem.currentSelectedGameObject == null) + return false; + + var data = GetBaseEventData(); + ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.updateSelectedHandler); + return data.used; + } + } +} diff --git a/Scripts/InputModules/GamePadInputModule.cs.meta b/Scripts/InputModules/GamePadInputModule.cs.meta new file mode 100644 index 0000000..a331d60 --- /dev/null +++ b/Scripts/InputModules/GamePadInputModule.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 26158f38115d49a4a915f46c7eced4ab +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Scripts/Layout/FlowLayoutGroup.cs b/Scripts/Layout/FlowLayoutGroup.cs index 00ff0c9..62886fd 100644 --- a/Scripts/Layout/FlowLayoutGroup.cs +++ b/Scripts/Layout/FlowLayoutGroup.cs @@ -165,7 +165,7 @@ namespace UnityEngine.UI.Extensions var h = CalculateRowVerticalOffset(groupHeight, yOffset, currentRowHeight); currentRowWidth -= SpacingX; // Layout the final row - LayoutRow(_rowList, currentRowWidth, currentRowHeight, workingWidth - SpacingX, padding.left, h, axis); + LayoutRow(_rowList, currentRowWidth, currentRowHeight, workingWidth - (_rowList.Count > 1 ? SpacingX : 0), padding.left, h, axis); } _rowList.Clear(); diff --git a/Scripts/Layout/ScrollSnap.cs b/Scripts/Layout/ScrollSnap.cs new file mode 100644 index 0000000..849f521 --- /dev/null +++ b/Scripts/Layout/ScrollSnap.cs @@ -0,0 +1,495 @@ +/// Credit BinaryX +/// Sourced from - http://forum.unity3d.com/threads/scripts-useful-4-6-scripts-collection.264161/page-2#post-1945602 +/// Updated by ddreaper - removed dependency on a custom ScrollRect script. Now implements drag interfaces and standard Scroll Rect. +/// Update by xesenix - rewrited almost entire code +/// - configuration for direction move instead of 2 concurrent class (easiear to change direction in editor) +/// - supports list layouted with horizontal or vertical layout need to match direction with type of layout used +/// - dynamicly checks if scrolled list size changes and recalculates anchor positions +/// and item size based on itemsVisibleAtOnce and size of root container +/// if you dont wish to use this auto resize turn of autoLayoutItems +/// - fixed current page made it independant from pivot +/// - replaced pagination with delegate function + +using System; +using UnityEngine.EventSystems; + +namespace UnityEngine.UI.Extensions +{ + [ExecuteInEditMode] + [RequireComponent(typeof(ScrollRect))] + [AddComponentMenu("UI/Extensions/Scroll Snap")] + public class ScrollSnap : MonoBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler + { + // needed becouse of reversed behavior of axis Y compared to X + // (positions of children lower in children list in horizontal directions grows when in vertical it gets smaller) + public enum ScrollDirection { + Horizontal, + Vertical + }; + + public delegate void PageSnapChange(int page); + + public event PageSnapChange onPageChange; + + public ScrollDirection direction = ScrollDirection.Horizontal; + + protected ScrollRect scrollRect; + protected RectTransform scrollRectTransform; + protected Transform listContainerTransform; + protected RectTransform rectTransform; + + protected int items = 0; + + int pages; + + protected int startingPage = 0; + + // anchor points to lerp to to see child on certain indexes + protected Vector3[] pageAnchorPositions; + protected Vector3 lerpTarget; + protected bool lerp; + + // item list related + protected float listContainerMinPosition; + protected float listContainerMaxPosition; + protected float listContainerSize; + protected RectTransform listContainerRectTransform; + protected Vector2 listContainerCachedSize; + + protected float itemSize; + + [Tooltip("Button to go to the next page. (optional)")] + public GameObject nextButton; + [Tooltip("Button to go to the previous page. (optional)")] + public GameObject prevButton; + + [Tooltip("Number of items visible in one page of scroll frame.")] + [RangeAttribute(1,100)] + public int itemsVisibleAtOnce = 1; + + [Tooltip("Sets minimum width of list items to 1/itemsVisibleAtOnce.")] + public bool autoLayoutItems = true; + + [Tooltip("If you wish to update scrollbar numberOfSteps to number of active children on list.")] + public bool linkScrolbarSteps = false; + + public Boolean useFastSwipe = true; + public int fastSwipeThreshold = 100; + + // drag related + protected bool startDrag = true; + protected Vector3 positionOnDragStart = new Vector3(); + protected int pageOnDragStart; + + protected bool fastSwipeTimer = false; + protected int fastSwipeCounter = 0; + protected int fastSwipeTarget = 10; + + // Use this for initialization + void Start() + { + lerp = false; + + scrollRect = gameObject.GetComponent (); + scrollRectTransform = gameObject.GetComponent (); + listContainerTransform = scrollRect.content; + listContainerRectTransform = listContainerTransform.GetComponent (); + + rectTransform = listContainerTransform.gameObject.GetComponent (); + UpdateListItemsSize(); + UpdateListItemPositions(); + + ChangePage (CurrentPage ()); + + if (nextButton) + { + nextButton.GetComponent