{"id":13661560,"url":"https://github.com/Haruma-K/UnityScreenNavigator","last_synced_at":"2025-04-25T03:30:38.492Z","repository":{"id":37021034,"uuid":"401345396","full_name":"Haruma-K/UnityScreenNavigator","owner":"Haruma-K","description":"Library for screen transitions, transition animations, transition history stacking, and screen lifecycle management in Unity's uGUI.","archived":false,"fork":false,"pushed_at":"2024-08-07T06:39:55.000Z","size":12212,"stargazers_count":945,"open_issues_count":1,"forks_count":77,"subscribers_count":13,"default_branch":"master","last_synced_at":"2024-11-06T13:11:56.495Z","etag":null,"topics":["navigation","ugui","unity"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Haruma-K.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-08-30T13:01:14.000Z","updated_at":"2024-11-05T09:33:14.000Z","dependencies_parsed_at":"2024-03-31T06:34:00.883Z","dependency_job_id":null,"html_url":"https://github.com/Haruma-K/UnityScreenNavigator","commit_stats":null,"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Haruma-K%2FUnityScreenNavigator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Haruma-K%2FUnityScreenNavigator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Haruma-K%2FUnityScreenNavigator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Haruma-K%2FUnityScreenNavigator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Haruma-K","download_url":"https://codeload.github.com/Haruma-K/UnityScreenNavigator/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223979480,"owners_count":17235406,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["navigation","ugui","unity"],"created_at":"2024-08-02T05:01:37.054Z","updated_at":"2024-11-10T16:31:09.556Z","avatar_url":"https://github.com/Haruma-K.png","language":"C#","readme":"\u003ch1 align=\"center\"\u003eUnity Screen Navigator\u003c/h1\u003e\n\n[![license](https://img.shields.io/badge/LICENSE-MIT-green.svg)](LICENSE.md)\n\n[日本語ドキュメント(Japanese Documents Available)](README_JA.md)\n\nLibrary for screen transitions, transition animations, transition history stacking, and screen lifecycle management in Unity's uGUI.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"80%\" src=\"https://user-images.githubusercontent.com/47441314/137313323-b2f24a0c-1ee3-4df0-a175-05fba32d9af3.gif\" alt=\"Demo\"\u003e\n\u003c/p\u003e\n\n## Table of Contents\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\u003cdetails\u003e\n\u003csummary\u003eDetails\u003c/summary\u003e\n\n- [Overview](#overview)\n    - [Features](#features)\n    - [Demo](#demo)\n- [Setup](#setup)\n    - [Requirement](#requirement)\n    - [Install](#install)\n- [Basic Screen Transition](#basic-screen-transition)\n    - [Concept of screens and transitions](#concept-of-screens-and-transitions)\n    - [Create page and transition](#create-page-and-transition)\n    - [Create modal and transition](#create-modal-and-transition)\n    - [Create sheet and transition](#create-sheet-and-transition)\n    - [How to wait for the transition](#how-to-wait-for-the-transition)\n    - [Getting containers with static methods](#getting-containers-with-static-methods)\n- [Screen Transition Animation](#screen-transition-animation)\n    - [Setting common transition animations](#setting-common-transition-animations)\n    - [Setting transition animation for each screen](#setting-transition-animation-for-each-screen)\n    - [Change transition animation according to partner screen](#change-transition-animation-according-to-partner-screen)\n    - [Screen transition animation and drawing order](#screen-transition-animation-and-drawing-order)\n    - [Create simple transition animations easily](#create-simple-transition-animations-easily)\n    - [Implement interactive animation with partner screen](#implement-interactive-animation-with-partner-screen)\n    - [Create animation with Timeline](#create-animation-with-timeline)\n- [Lifecycle Events](#lifecycle-events)\n    - [Lifecycle events of the page](#lifecycle-events-of-the-page)\n    - [Lifecycle events of the modal](#lifecycle-events-of-the-modal)\n    - [Lifecycle events of the sheet](#lifecycle-events-of-the-sheet)\n    - [Use async methods instead of coroutines](#use-async-methods-instead-of-coroutines)\n- [Loading Screen Resources](#loading-screen-resources)\n    - [Change the loading method of screen resources](#change-the-loading-method-of-screen-resources)\n    - [Use Addressable Asset System for the loading](#use-addressable-asset-system-for-the-loading)\n    - [Load synchronously](#load-synchronously)\n    - [Preloading](#preloading)\n- [Other Features](#other-features)\n    - [Pop multiple screens at once](#pop-multiple-screens-at-once)\n    - [Don't stack pages in history](#dont-stack-pages-in-history)\n    - [Change the backdrop of modals](#change-the-backdrop-of-modals)\n    - [Close the active modal when the backdrop is clicked](#close-the-active-modal-when-the-backdrop-is-clicked)\n    - [Enable interaction during transitions](#enable-interaction-during-transitions)\n    - [Disable masking for container](#disable-masking-for-container)\n    - [Get information about playing animation information](#get-information-about-playing-animation-information)\n    - [Use loaded Prefab instances when loading screens](#use-loaded-prefab-instances-when-loading-screens)\n- [FAQ](#faq)\n    - [How to make each Screen with Scene instead of Prefab](#how-to-make-each-screen-with-scene-instead-of-prefab)\n    - [How to separate view and logic](#how-to-separate-view-and-logic)\n    - [How to pass data to each screen](#how-to-pass-data-to-each-screen)\n    - [How to reuse popped pages or modals](#how-to-reuse-popped-pages-or-modals)\n- [License](#license)\n\n\u003c/details\u003e\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## Overview\n\n#### Features\n* You can create pages, modals, tabs and their transitions easily and flexibly.\n* Manage screen lifecycle and memory from load to destroy.\n* Separated workflow with animators for complex screen transition animations.\n* Well-separated library with no extra functions (ex. GUI library, state machine).\n* And standard features such as history stacking and click prevention during transitions.\n\n#### Demo\nYou can play the demo scene with the following steps.\n\n1. Clone this repository.\n2. Open and play the following scene.\n    * https://github.com/Haruma-K/UnityScreenNavigator/blob/master/Assets/Demo/Core/DemoEntryPoint.unity\n\nPlease note that some of the images used in this demo are from the following free contents.  \nFor more information, including copyright, please refer to the following website.\n\n* [JewelSaviorFREE](http://www.jewel-s.jp/)\n\n## Setup\n\n#### Requirement\n* Unity 2021.3 or higher\n* uGUI (UIElements not supported)\n\n#### Install\n1. Open the Package Manager from Window \u003e Package Manager\n2. \"+\" button \u003e Add package from git URL\n3. Enter the following to install\n   * https://github.com/Haruma-K/UnityScreenNavigator.git?path=/Assets/UnityScreenNavigator\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"80%\" src=\"https://user-images.githubusercontent.com/47441314/118421190-97842b00-b6fb-11eb-9f94-4dc94e82367a.png\" alt=\"Package Manager\"\u003e\n\u003c/p\u003e\n\nOr, open Packages/manifest.json and add the following to the dependencies block.\n\n```json\n{\n    \"dependencies\": {\n        \"com.harumak.unityscreennavigator\": \"https://github.com/Haruma-K/UnityScreenNavigator.git?path=/Assets/UnityScreenNavigator\"\n    }\n}\n```\n\nIf you want to set the target version, specify it like follow.\n\n* https://github.com/Haruma-K/UnityScreenNavigator.git?path=/Assets/UnityScreenNavigator#1.0.0\n\n## Basic Screen Transition\n\n#### Concept of screens and transitions\nUnity Screen Navigator classifies screens into three types: \"Page\", \"Modal\" and \"Sheet\".\n\n\"Page\" is a screen that transitions in sequence.  \nFor example, when you transition from the Page A to Page B, Page A will be stacked in the history.  \nAnd when you return from Page B, Page A will be redisplayed with its states intact.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"50%\" src=\"https://user-images.githubusercontent.com/47441314/136680850-2aca1977-02c2-4730-a0d8-603934f71c80.gif\" alt=\"Demo\"\u003e\n\u003c/p\u003e\n\n\"Modal\" is a screen that is stacked in a window.  \nWhen it is displayed, all interactions except for the foreground modal will be blocked.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"50%\" src=\"https://user-images.githubusercontent.com/47441314/136698982-21ff5172-e38d-4d80-a976-a7ecc511c048.gif\" alt=\"Demo\"\u003e\n\u003c/p\u003e\n\nAnd \"Sheet\" is used for tab-like GUI.  \nHistory is not managed, and only one active screen is displayed.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"50%\" src=\"https://user-images.githubusercontent.com/47441314/136700074-2a4fa134-dc5d-4b72-90d8-f6b12c91fc0f.gif\" alt=\"Demo\"\u003e\n\nThese screens can be nested.  \nAnd, the area of each screen can be freely specified (not necessarily the entire window).\n\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"50%\" src=\"https://user-images.githubusercontent.com/47441314/137634860-ae202ce7-5d2d-48b1-a938-358381d16780.gif\" alt=\"Demo\"\u003e\n\u003c/p\u003e\n\n#### Create page and transition\nTo create the page transition, first attach the \"Page Container\" component to an GameObject under the Canvas.  \nThe pages will be displayed to fit it, so adjust the size.\n\nNext, attach the `Page` component to the root GameObject of the page view.  \nPlace this GameObject under the Resources folder with an arbitrary name.\n\nAnd call `PageContainer.Push()` with the Resources path to display the page.  \nThe following is an example of pushing the page placed in `Assets/Resources/ExamplePage.prefab`.\n\n```cs\nPageContainer pageContainer;\n\n// Push the page named \"ExamplePage\".\nvar handle = pageContainer.Push(\"ExamplePage\", true);\n\n// Wait for the transition to finish.\nyield return handle;\n//await handle.Task; // You can also use await.\n//handle.OnTerminate += () =\u003e { }; // You can also use callback.\n```\n\nAlso, use `PageContainer.Pop()` to discard the active page and display the previous page.\n\n```cs\nPageContainer pageContainer;\n\n// Pop the active page.\nvar handle = pageContainer.Pop(true);\n\n// Wait for the transition to finish.\nyield return handle;\n```\n\nIf you want to skip a certain page when call `Pop()`, you can [disable stacking to history](#Dont-stack-pages-in-history) by using the optional argument.\n\n#### Create modal and transition\nTo create the modal transition, first attach the \"Modal Container\" component to an GameObject under the Canvas.  \nIn general, modals are designed to cover the entire window with their backdrop and block clicks.  \nTherefore, the size of the RectTransform of the GameObject should basically be set to match the window size.\n\nNext, attach the `Modal` component to the root GameObject of the modal view.  \nThis root GameObject will be adjusted to fit the size of the `Modal Container`.  \nSo if you want to create the modal with margins, create a child GameObject with a smaller size and create the content inside it.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"70%\" src=\"https://user-images.githubusercontent.com/47441314/136698661-e4e247b6-7938-4fb5-8f6f-f2897f42eebe.png\" alt=\"Demo\"\u003e\n\u003c/p\u003e\n\nPlace this GameObject under the Resources folder with an arbitrary name.\n\nAnd call `ModalContainer.Push()` with the Resources path to display the page.  \nThe following is an example of pushing the modal placed in `Assets/Resources/ExampleModal.prefab`.\n\n```cs\nModalContainer modalContainer;\n\n// Push the modal named \"ExampleModal\".\nvar handle = modalContainer.Push(\"ExampleModal\", true);\n\n// Wait for the transition to finish.\nyield return handle;\n//await handle.Task; // You can also use await.\n//handle.OnTerminate += () =\u003e { }; // You can also use callback.\n```\n\nAlso, use `ModalContainer.Pop()` to discard the active modal and display the previous modal.\n\n```cs\nModalContainer modalContainer;\n\n// Pop the active modal.\nvar handle = modalContainer.Pop(true);\n\n// Wait for the transition to finish.\nyield return handle;\n```\n\nNote that [you can change the modal backdrop](#Change-the-backdrop-of-modals) as you like.\n\n#### Create sheet and transition\nTo create the sheet transition, first attach the \"Sheet Container\" component to an GameObject under the Canvas.  \nThe sheets will be displayed to fit it, so adjust the size.\n\nNext, attach the `Sheet` component to the root GameObject of the sheet view.  \nPlace this GameObject under the Resources folder with an arbitrary name.\n\nCall `SheetContainer.Register()` with the Resources path to create the sheet.  \nAfter it is created, you can change the active sheet by calling `SheetContainer.Show()`.  \nAt this time, if there is already an active sheet, it will be deactivated.\n\nThe following is an example of displaying the sheet placed in `Assets/Resources/ExampleSheet.prefab`.\n\n```cs\nSheetContainer sheetContainer;\n\n// Instantiate the sheet named \"ExampleSheet\"\nvar registerHandle = sheetContainer.Register(\"ExampleSheet\");\nyield return registerHandle;\n\n// Show the sheet named \"ExampleSheet\"\nvar showHandle = sheetContainer.Show(\"ExampleSheet\", false);\nyield return showHandle;\n```\n\nNote that when multiple sheets with same resource keys are instantiated by the `Register()` method, the identity of the sheet instance cannot guaranteed by the resource key.  \nIn such case, use the sheet ID instead of the resource key, as shown below.\n\n```cs\nSheetContainer sheetContainer;\n\n// Instantiate the sheet named \"ExampleSheet\" and get the sheet id.\nvar sheetId = 0;\nvar registerHandle = sheetContainer.Register(\"ExampleSheet\", x =\u003e\n{\n    sheetId = x.sheetId;\n});\nyield return registerHandle;\n\n// Show the sheet with sheetId.\nvar showHandle = sheetContainer.Show(sheetId, false);\nyield return showHandle;\n```\n\nAlso, to hide the active sheet instead of switching it, use the `Hide()` method.\n\n```cs\nSheetContainer sheetContainer;\n\n// Hide the active sheet.\nvar handle = sheetContainer.Hide(true);\n\n// Wait for the transition to finish.\nyield return handle;\n```\n\n#### How to wait for the transition\nEach method for transition returns `AsyncProcessHandle` as the return value.  \nUsing this object, you can wait for the transition process to finish.\n\nYou can use coroutines, asynchronous methods, and callbacks to do this.  \nTo wait in a coroutine, use `yield return` as shown below.\n\n```cs\nyield return pageContainer.Push(\"ExamplePage\", true);\n```\n\nTo wait in an asynchronous method, use await for `AsyncProcessHandle.Task` as follows.\n\n```cs\nawait pageContainer.Push(\"ExamplePage\", true).Task;\n```\n\nAnd use `AsyncProcessHandle.OnTerminate` if you want to use a callback.\n\n```cs\npageContainer.Push(\"ExamplePage\", true).OnTerminate += () =\u003e { };\n```\n\n#### Getting containers with static methods\nEach container (`PageContainer`/`ModalContainer`/`SheetContainer`) has static methods to get the instance.\n\nUsing the `Container.Of()` as follows, you can get the container that is attached to the nearest parent from the given Transform or RectTransform.\n\n```cs\nvar pageContainer = PageContainer.Of(transform);\nvar modalContainer = ModalContainer.Of(transform);\nvar sheetContainer = SheetContainer.Of(transform);\n```\n\nAlso, you can set the `Name` property in the container's Inspector to get the container by its name.  \nIn this case, use the `Container.Find()` method as follows.\n\n```cs\nvar pageContainer = PageContainer.Find(\"SomePageContainer\");\nvar modalContainer = ModalContainer.Find(\"SomeModalContainer\");\nvar sheetContainer = SheetContainer.Find(\"SomeSheetContainer\");\n```\n\n## Screen Transition Animation\n\n#### Setting common transition animations\nIn default, a standard transition animation is set for each screen type.\n\nYou can create a class derived from `TransitionAnimationObject` to create custom transition animation.  \nThis class has a property and methods to define the animation behavior.\n\n```cs\n// Duration (sec).\npublic abstract float Duration { get; }\n\n// Initialize.\npublic abstract void Setup();\n\n// Define the state at this time.\npublic abstract void SetTime(float time);\n```\n\nPlease refer to [SimpleTransitionAnimationObject](https://github.com/Haruma-K/UnityScreenNavigator/blob/master/Assets/UnityScreenNavigator/Runtime/Core/Shared/SimpleTransitionAnimationObject.cs) for the practical implementation.\n\nThen, instantiate this Scriptable Object, and assign it to `UnityScreenNavigatorSettings`.  \nYou can create `UnityScreenNavigatorSettings` from `Assets \u003e Create \u003e Screen Navigator Settings`.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"60%\" src=\"https://user-images.githubusercontent.com/47441314/137321487-e2267184-6eba-46a7-9f4e-468176822408.png\"\u003e\n\u003c/p\u003e\n\n#### Setting transition animation for each screen\nYou can also set up different animation for each screen.\n\nEach Page, Modal, and Sheet component has the `Animation Container` property.  \nYou can set the transition animation to it.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"60%\" src=\"https://user-images.githubusercontent.com/47441314/137632127-2e224b47-3ef1-4fdd-a64a-986b38d5ea6a.png\"\u003e\n\u003c/p\u003e\n\nYou can change the transition animation of this screen by setting the `Asset Type` to `Scriptable Object` and assigning the `TransitionAnimationObject` described in the previous section to `Animation Object`.\n\nAlso, you can use the MonoBehaviour instead of the ScriptableObject.  \nIn this case, first create a class that extends `TransitionAnimationBehaviour` .  \nPlease refer to [SimpleTransitionAnimationBehaviour](https://github.com/Haruma-K/UnityScreenNavigator/blob/master/Assets/UnityScreenNavigator/Runtime/Core/Shared/SimpleTransitionAnimationBehaviour.cs) for the practical implementation.\n\nThen, attach this component and set the `Asset Type` to `Mono Behaviour` and assign the reference to `Animation Behaviour`.\n\n#### Change transition animation according to partner screen\nFor example, when screen A enters and screen B exits, screen B is called the \"Partner Screen\" of screen A.\n\nIf you enter the name of the partner screen in the property shown below, the transition animation will be applied only when this name matches the partner screen name.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"60%\" src=\"https://user-images.githubusercontent.com/47441314/137632918-9d777817-d2dc-43c9-bd7e-c6a1713a5f26.png\"\u003e\n\u003c/p\u003e\n\nIn default, the prefab name is used as the screen name.  \nIf you want to name it explicitly, uncheck `Use Prefab Name As Identifier` and enter a name in the `Identifier` property.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"60%\" src=\"https://user-images.githubusercontent.com/47441314/137632986-f5727a42-4c27-48aa-930d-e7b0673b978f.png\"\u003e\n\u003c/p\u003e\n\nIn addition, regular expressions can be used for the `Partner Page Identifier Regex`.  \nAnd if multiple animations are set, they will be evaluated in order from top.\n\n#### Screen transition animation and drawing order\nIn the transition animation of a screen with a partner screen, the drawing order can be important.  \nFor example, an animation where the screen covers the partner screen.\n\nIf you want to control the drawing order, use the `Rendering Order` property.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"60%\" src=\"https://user-images.githubusercontent.com/47441314/137633021-4e864c77-baa0-4d42-a8e7-b0183f7302f5.png\"\u003e\n\u003c/p\u003e\n\nDuring screen transitions, the screen is drawn in the order of decreasing this value.\n\nNote that modals do not have a `Rendering Order` property, since the newest one is always displayed in front.\n\n#### Create simple transition animations easily\nYou can use `SimpleTransitionAnimationObject` as a simple transition animation implementation.\n\nThis can be created from `Assets \u003e Create \u003e Screen Navigator \u003e Simple Transition Animation`.  \nThen, a ScriptableObject as shown below will be generated, and you can set up the animation from the Inspector.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"60%\" src=\"https://user-images.githubusercontent.com/47441314/137326944-112e0254-cd27-4d49-a32b-9c436b9537e4.png\"\u003e\n\u003c/p\u003e\n\nYou can also use `SimpleTransitionAnimationBehaviour` as a MonoBehaviour implementation of this.  \nThis is used by attaching it directly to a GameObject.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"60%\" src=\"https://user-images.githubusercontent.com/47441314/137326555-90cdce8d-98da-4a00-99cc-5a65c1086760.png\"\u003e\n\u003c/p\u003e\n\nDescription of each property is as follows.\n\n|Property Name|Description|\n|-|-|\n|Delay|Delay time before the animation starts (seconds).|\n|Duration|Animation duration (seconds).|\n|Ease Type|Type of the easing functions.|\n|Before Alignment|Relative position from the container before transition.|\n|Before Scale|Scale before transition.|\n|Before Alpha|Transparency before transition.|\n|After Alignment|Relative position from the container after transition.|\n|After Scale|Scale after transition.|\n|After Alpha|Transparency after transition.|\n\n#### Implement interactive animation with partner screen\nYou can also create animations that refer to the state of the partner screen.  \nIn the following example, the image of the previous modal is enlarged while seamlessly transitioning to the next modal.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"60%\" src=\"https://user-images.githubusercontent.com/47441314/137315378-974395a8-f910-41a9-8e07-2964efded848.gif\"\u003e\n\u003c/p\u003e\n\nTo implement this, first create a class that derived from `TransitionAnimationObject` or `TransitionAnimationBehaviour`.  \nThen, refer to the `PartnerRectTransform` property to get the partner screen.  \nIf the partner screen does not exist, `PartnerRectTransform` will be null.\n\nPlease refer to [CharacterImageModalTransitionAnimation](https://github.com/Haruma-K/UnityScreenNavigator/blob/master/Assets/Demo/Scripts/CharacterImageModalTransitionAnimation.cs) in demo for the practical implementation.\n\n#### Create animation with Timeline\nYou can use Timeline to create transition animation.  \nIt is recommended to use Timeline for complex transition animation.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"60%\" src=\"https://user-images.githubusercontent.com/47441314/137634258-135b454e-04b5-49e8-a87a-bfb6ede03f49.gif\"\u003e\n\u003c/p\u003e\n\nTo implement this, first attach the `Timeline Transition Animation Behaviour` to a GameObject.  \nAnd assign `Playable Director` and `Timeline Asset` to properties.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"60%\" src=\"https://user-images.githubusercontent.com/47441314/137633599-dd8b204e-e6ec-46bf-b93c-ee54b4ac3d59.png\"\u003e\n\u003c/p\u003e\n\n`Play On Awake` property of `Playable Director` need to be unchecked.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"60%\" src=\"https://user-images.githubusercontent.com/47441314/137633492-4d837177-a381-486f-8942-df26e522da91.png\"\u003e\n\u003c/p\u003e\n\nFinally, assign this `Timeline Transition Animation Behaviour` to the `Animation Container`.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"60%\" src=\"https://user-images.githubusercontent.com/47441314/137633821-1fa1a8d6-ca41-49ca-aacf-dcf7f744c0b1.png\"\u003e\n\u003c/p\u003e\n\nIn addition, I recommend [UnityUIPlayables](https://github.com/Haruma-K/UnityUIPlayables) to create uGUI animations with Timeline.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"60%\" src=\"https://user-images.githubusercontent.com/47441314/113313016-cf9afe80-9345-11eb-9aa9-422c53b5a3f8.gif\"\u003e\n\u003c/p\u003e\n\n## Lifecycle Events\n\n#### Lifecycle events of the page\nBy overriding following methods in the class derived from the `Page` class,  \nyou can write the processes associated with the lifecycle of the page.\n\n```cs\nusing System.Collections;\nusing UnityScreenNavigator.Runtime.Core.Page;\n\npublic class SomePage : Page\n{\n    // Called just after this page is loaded.\n    public override IEnumerator Initialize() { yield break; }\n    // Called just before this page is released.\n    public override IEnumerator Cleanup() { yield break; }\n    // Called just before this page is displayed by the Push transition.\n    public override IEnumerator WillPushEnter() { yield break; }\n    // Called just after this page is displayed by the Push transition.\n    public override void DidPushEnter() { }\n    // Called just before this page is hidden by the Push transition.\n    public override IEnumerator WillPushExit() { yield break; }\n    // Called just after this page is hidden by the Push transition.\n    public override void DidPushExit() { }\n    // Called just before this page is displayed by the Pop transition.\n    public override IEnumerator WillPopEnter() { yield break; }\n    // Called just after this page is displayed by the Pop transition.\n    public override void DidPopEnter() { }\n    // Called just before this page is hidden by the Pop transition.\n    public override IEnumerator WillPopExit() { yield break; }\n    // Called just after this page is hidden by the Pop transition.\n    public override void DidPopExit() { }\n}\n```\n\nYou can also register lifecycle events externally by `Page.AddLifecycleEvents()` as below.\n\n```cs\n// IPageLifecycleEvent is the interface that has lifecycle events described above.\n// You can specify the execution priority with the second argument.\n//  Less than 0: executed before Page lifecycle event.\n//  Greater than 0: executed after Page lifecycle event.\nIPageLifecycleEvent lifecycleEventImpl;\nPage page;\npage.AddLifecycleEvent(lifecycleEventImpl, -1);\n\n// It is also possible to register only some lifecycle events as follows.\nIEnumerator OnWillPushEnter()\n{\n    // Some code.\n    yield break;\n}\npage.AddLifecycleEvent(onWillPushEnter: OnWillPushEnter);\n```\n\nAnd you can also hook transition events from the container by passing object that implements `IPageContainerCallbackReceiver` to `PageContainer.AddCallbackReceiver()`.\n\n```cs\npublic interface IPageContainerCallbackReceiver\n{\n    // Called just before the Push transition is executed.\n    void BeforePush(Page enterPage, Page exitPage);\n    // Called just after the Push transition is executed.\n    void AfterPush(Page enterPage, Page exitPage);\n    // Called just before the Pop transition is executed.\n    void BeforePop(Page enterPage, Page exitPage);\n    // Called just after the Pop transition is executed.\n    void AfterPop(Page enterPage, Page exitPage);\n}\n```\n\nNote that if you implement `IPageContainerCallbackReceiver` to `MonoBehaviour` and attach it to GameObject of the container,  \nit will be registered to `PageContainer` without calling `PageContainer.AddCallbackReceiver()`.\n\n#### Lifecycle events of the modal\nBy overriding following methods in the class derived from the `Modal` class,  \nyou can write the processes associated with the lifecycle of the modal.\n\n```cs\nusing System.Collections;\nusing UnityScreenNavigator.Runtime.Core.Modal;\n\npublic class SomeModal : Modal\n{\n    // Called just after this modal is loaded.\n    public override IEnumerator Initialize() { yield break; }\n    // Called just before this modal is released.\n    public override IEnumerator Cleanup() { yield break; }\n    // Called just before this model is displayed by the Push transition.\n    public override IEnumerator WillPushEnter() { yield break; }\n    // Called just after this modal is displayed by the Push transition.\n    public override void DidPushEnter() { }\n    // Called just before this modal is hidden by the Push transition.\n    public override IEnumerator WillPushExit() { yield break; }\n    // Called just after this modal is hidden by the Push transition.\n    public override void DidPushExit() { }\n    // Called just before this modal is displayed by the Pop transition.\n    public override IEnumerator WillPopEnter() { yield break; }\n    // Called just after this modal is displayed by the Pop transition.\n    public override void DidPopEnter() { }\n    // Called just before this modal is hidden by the Pop transition.\n    public override IEnumerator WillPopExit() { yield break; }\n    // Called just after this modal is hidden by the Pop transition.\n    public override void DidPopExit() { }\n}\n```\n\nYou can also register lifecycle events externally by `Modal.AddLifecycleEvents()` as below.\n\n```cs\n// IModalLifecycleEvent is the interface that has lifecycle events described above.\n// You can specify the execution priority with the second argument.\n//  Less than 0: executed before Modal lifecycle event.\n//  Greater than 0: executed after Modal lifecycle event.\nIModalLifecycleEvent lifecycleEventImpl;\nModal modal;\nModal.AddLifecycleEvent(lifecycleEventImpl, -1);\n\n// It is also possible to register only some lifecycle events as follows.\nIEnumerator OnWillPushEnter()\n{\n    // Some code.\n    yield break;\n}\nmodal.AddLifecycleEvent(onWillPushEnter: OnWillPushEnter);\n```\n\nAnd you can also hook transition events from the container by passing object that implements `IModalContainerCallbackReceiver` to `ModalContainer.AddCallbackReceiver()`.\n\n```cs\npublic interface IModalContainerCallbackReceiver\n{\n    // Called just before the Push transition is executed.\n    void BeforePush(Modal enterModal, Modal exitModal);\n    // Called just after the Push transition is executed.\n    void AfterPush(Modal enterModal, Modal exitModal);\n    // Called just before the Pop transition is executed.\n    void BeforePop(Modal enterModal, Modal exitModal);\n    // Called just after the Pop transition is executed.\n    void AfterPop(Modal enterModal, Modal exitModal);\n}\n```\n\nNote that if you implement `IModalContainerCallbackReceiver` to `MonoBehaviour` and attach it to GameObject of the container,  \nit will be registered to `ModalContainer` without calling `ModalContainer.AddCallbackReceiver()`.\n\n#### Lifecycle events of the sheet\nBy overriding following methods in the class derived from the `Sheet` class,  \nyou can write the processes associated with the lifecycle of the sheet.\n\n```cs\nusing System.Collections;\nusing UnityScreenNavigator.Runtime.Core.Sheet;\n\npublic class SomeSheet : Sheet\n{\n    // Called just after this sheet is loaded.\n    public override IEnumerator Initialize() { yield break; }\n    // Called just before this sheet is released.\n    public override IEnumerator Cleanup() { yield break; }\n    // Called just before this sheet is displayed.\n    public override IEnumerator WillEnter() { yield break; }\n    // Called just after this sheet is displayed.\n    public override void DidEnter() { }\n    // Called just before this sheet is hidden.\n    public override IEnumerator WillExit() { yield break; }\n    // Called just after this sheet is hidden.\n    public override void DidExit() { }\n}\n```\n\nYou can also register lifecycle events externally by `Sheet.AddLifecycleEvents()` as below.\n\n```cs\n// ISheetLifecycleEvent is the interface that has lifecycle events described above.\n// You can specify the execution priority with the second argument.\n//  Less than 0: executed before Sheet lifecycle event.\n//  Greater than 0: executed after Sheet lifecycle event.\nISheetLifecycleEvent lifecycleEventImpl;\nSheet sheet;\nSheet.AddLifecycleEvent(lifecycleEventImpl, -1);\n\n// It is also possible to register only some lifecycle events as follows.\nIEnumerator OnWillEnter()\n{\n    // Some code.\n    yield break;\n}\nsheet.AddLifecycleEvent(onWillEnter: OnWillEnter);\n```\n\nAnd you can also hook transition events from the container by passing object that implements `ISheetContainerCallbackReceiver` to `SheetContainer.AddCallbackReceiver()`.\n\n```cs\npublic interface ISheetContainerCallbackReceiver\n{\n    // Called just before the Show transition is executed.\n    void BeforeShow(Sheet enterSheet, Sheet exitSheet);\n    // Called just after the Show transition is executed.\n    void AfterShow(Sheet enterSheet, Sheet exitSheet);\n    // Called just before the Hide transition is executed.\n    void BeforeHide(Sheet exitSheet);\n    // Called just after the Hide transition is executed.\n    void AfterHide(Sheet exitSheet);\n}\n```\n\nNote that if you implement `ISheetContainerCallbackReceiver` to `MonoBehaviour` and attach it to GameObject of the container,  \nit will be registered to `SheetContainer` without calling `SheetContainer.AddCallbackReceiver()`.\n\n#### Use async methods instead of coroutines\nYou can also use asynchronous methods instead of coroutines to define lifecycle events, as shown below.\n\n```cs\nusing System.Threading.Tasks;\nusing UnityScreenNavigator.Runtime.Core.Page;\n\npublic class SomePage : Page\n{\n    // Using asynchronous methods to define lifecycle events\n    public override async Task Initialize()\n    {\n        await Task.Delay(100);\n    }\n}\n```\n\nTo use asynchronous methods, add `Scripting Define Symbols` in the following steps.\n\n* Player Settings \u003e Other Settings\n* Add `USN_USE_ASYNC_METHODS` to `Scripting Define Symbols`.\n\nNote that `Scripting Define Symbols` needs to be set for all platforms.\n\n## Loading Screen Resources\n\n#### Change the loading method of screen resources\nAs mentioned above, by default, the resources of each screen are placed in the Resources folder as Prefab.\n\nIf you want to change the loading method, first create the Scriptable Object derived from `AssetLoaderObject`.  \n`AssetLoaderObject` is an implementation of `IAssetLoader`, and has the following methods.\n\n```cs\n// Load the resource indicated by the key.\npublic abstract AssetLoadHandle\u003cT\u003e Load\u003cT\u003e(string key) where T : Object;\n\n// Asynchronously load the resource indicated by the key.\npublic abstract AssetLoadHandle\u003cT\u003e\n\n// Release the resource indicated by the handle.\npublic abstract void Release(AssetLoadHandle handle);\n```\n\nPlease refer to [ResourcesAssetLoader](https://github.com/Haruma-K/UnityScreenNavigator/blob/master/Assets/UnityScreenNavigator/Runtime/Foundation/AssetLoader/ResourcesAssetLoader.cs) for the practical implementation.  \nAfter create it, assign it's instance to `AssetLoader` property of `UnityScreenNavigatorSettings`.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"60%\" src=\"https://user-images.githubusercontent.com/47441314/137721037-18c84aad-28d3-4dd8-9a4a-4450a80badd2.png\"\u003e\n\u003c/p\u003e\n\nYou can create `UnityScreenNavigatorSettings` from `Assets \u003e Create \u003e Screen Navigator Settings`.\n\nYou can also set the `IAssetLoader`for each container by setting the `AssetLoader` property of each `Container`.\n\n#### Use Addressable Asset System for the loading\nAn implementation of `IAssetLoader` for the Addressable Asset System is provided by default.  \nIf you want to load each screen with an address, follow the steps below to set it up.\n\n1. Select `Assets \u003e Create \u003e Resource Loader \u003e Addressable Asset Loader`\n2. Assign the ScriptableObject created in step 1 to the `AssetLoader` property of `UnityScreenNavigatorSettings`.\n\n#### Load synchronously\nYou can pass false as the `loadAsync` argument of each container's transition method to load the screen synchronously.  \nFor example, `PageContainer.Push()` should be written as follows.\n\n```cs\nPageContainer container;\n\n// Load synchronously.\nvar handle = container.Push(\"FooPage\", true, loadAsync: false);\n\n// Wait for the end of the transition animation.\nyield return handle;\n```\n\nIn addition, you can initialize it in same frame as the transition method call by using `onLoad` callback together.\n\n```cs\nPageContainer container;\n\n// Load synchronously and receive the callback after loading.\nvar handle = container.Push(\"FooPage\", true, loadAsync: false, onLoad: x =\u003e\n{\n    // Initialize page. (Called in the same frame as Push)\n    x.page.Setup();\n});\n\n// Wait for the end of the transition animation.\nyield return handle;\n```\n\nNote that if you use `AddressableAssetLoader` and load synchronously, Addressables 1.17.4 or higher is required.  \nIn addition, there are performance cautions due to [Addressable's specifications](https://docs.unity3d.com/Packages/com.unity.addressables@1.17/manual/SynchronousAddressables.html).\n\n#### Preloading\nThe pages and the modals are loaded only after a screen transition is requested.  \nWhen loading a large resource, it may take a long time to load and prevent smooth transitions.\n\nIn such a case, it is useful to preload resources in advance.  \nThe following is an example of preloading with `PageContainer`.\n\n```cs\nconst string pageName = \"FooPage\";\nPageContainer container;\n\n// Preload FooPage.\nvar preloadHandle = container.Preload(pageName);\n\n// Wait for the end of the preloading.\nyield return preloadHandle;\n\n// Transition smoothly because FooPage has been preloaded.\ncontainer.Push(pageName, true);\n\n// Release the preloaded FooPage.\ncontainer.ReleasePreloaded(pageName);\n```\n\nPlease refer to [HomePage in demo](https://github.com/Haruma-K/UnityScreenNavigator/blob/master/Assets/Demo/Scripts/HomePage.cs) for the practical implementation.  \nWhen the `Home` page is initialized, the `Shop` page is also loaded and destroyed at the same time.\n\n## Other Features\n\n#### Pop multiple screens at once\nIn `PageContainer` and `Modal Container`, you can pop multiple screens at once.\nTo do this, specify the number of screens to be popped in the second argument of `PageContainer.Pop()` or `ModalContainer.Pop()`.\n\n```cs\nPageContainer pageContainer;\npageContainer.Pop(true, 2);\n\nModalContainer modalContainer;\nmodalContainer.Pop(true, 2);\n```\n\nYou can also specify the destination `PageID` or `ModalID`.\n`PageID` and `ModalID` can be obtained using the `onLoad` callback of `Push()` as shown below.\n\n\n```cs\nPageContainer pageContainer;\npageContainer.Push(\"fooPage\", true, onLoad: x =\u003e\n{\n    var pageId = x.pageId;\n});\n\nModalContainer modalContainer;\nmodalContainer.Push(\"fooModal\", true, onLoad: x =\u003e\n{\n    var modalId = x.modalId;\n});\n```\n\nIn addition, you can specify any ID by specifying the `pageId` or `modalId` argument of `Push()`.\n\n```cs\nPageContainer pageContainer;\npageContainer.Push(\"fooPage\", true, pageId: \"MyPageID\");\n\nModalContainer modalContainer;\nmodalContainer.Push(\"fooModal\", true, modalId: \"MyModalID\");\n```\n\nIn addition, for the pages or modals that are skipped when popping multiple screens, the lifecycle events before and after transition will not be called, only the event before destroying will be called.\nIn `PageContainer`, the transition animation of the skipping pages will not be played.\nIn `ModalContainer`, the transition animation when the skipped modals are closed will be played simultaneously.\n\n#### Don't stack pages in history\nThere are some pages that you want to skip on transition back, such as loading screen.\n\nIn such a case, you can prevent the page from being stacked in the history by setting the optional argument `stack` to `false` in the `PageContainer.Push()`.   \nThe instance of this page will be disposed when transitioning to the next page, and thus skipped when backing.\n\n```cs\nPageContainer container;\n\n// Transition to FooPage without stacking it in the history.\nyield return container.Push(\"FooPage\", true, stack: false);\n\n// Transition to BarPage, and FooPage is disposed.\nyield return container.Push(\"BarPage\", true);\n\n// When Pop, it does not back to FooPage, but to the page before it.\nyield return container.Pop(true);\n```\n\nPlease refer to [TopPage in demo](https://github.com/Haruma-K/UnityScreenNavigator/blob/master/Assets/Demo/Scripts/TopPage.cs) for the practical implementation.  \nTransition to the loading page without stacking.\n\n#### Change the backdrop of modals\nIn default, a black semi-transparent screen is set as the modal backdrop.  \nYou can change this in the settings.\n\nTo do this, first attach the `Modal Backdrop` component to the modal backdrop view, and make it a prefab.\n\nNext, assign this prefab as the modal backdrop.  \nTo change the modal backdrop of the whole application, assign it to `Modal Backdrop Prefab` in `UnityScreenNavigatorSettings`.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"60%\" src=\"https://user-images.githubusercontent.com/47441314/137837643-f5c7cc13-a379-4c0f-9c34-1e9c19869136.png\"\u003e\n\u003c/p\u003e\n\nYou can create `UnityScreenNavigatorSettings` from `Assets \u003e Create \u003e Screen Navigator Settings`.\n\nYou can also set the backdrop for each `Modal Container` by assigning the prefab to the `Override Backdrop Prefab` of the `Modal Container`.\n\n#### Close the active modal when the backdrop is clicked\nIn default, the backdrop is not clickable.  \nIf you want to close the active modal when the backdrop is clicked, first change the backdrop by the steps above.  \nThen, check the **Close Modal When Clicked** option of the **Modal Backdrop** component.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=500 src=\"https://user-images.githubusercontent.com/47441314/182382933-14af7d19-50e4-4cbc-ac89-bd9702df26af.png\"\u003e\n\u003c/p\u003e\n\n#### Enable interaction during transitions\nFrom the start of transition to the end, interactions of all containers such as clicking on the screen are disabled.\n\nYou can change the settings by changing `Enable Interaction In Transition` and `Control Interactions Of All Containers` property of `UnityScreenNavigatorSettings`.\nIn default, `Enable Interaction In Transition` is `false` and `Control Interactions Of All Containers` is `true`.\n\nTo enable interaction during transitions, set `Enable Interaction In Transition` to `true`.\nAnd if you want to disable interaction only for the container that is currently transitioning, keep `Enable Interaction In Transition` to `false` and set `Control Interactions Of All Containers` to `false`.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"60%\" src=\"https://user-images.githubusercontent.com/47441314/200176139-4de8c94e-60f4-4db9-8abf-7b6d50bea09e.png\"\u003e\n\u003c/p\u003e\n\nYou can create `UnityScreenNavigatorSettings` from `Assets \u003e Create \u003e Screen Navigator Settings`.\n\nHowever, it is not possible to transition to other screen while transitioning in one container.  \nSo you need to control the transition timing appropriately if you enable interaction.\n\n#### Disable masking for container\nBy default, the part of the screen under the container that is outside the container is masked.  \nIf you want to show the screen outside the container, uncheck the `Rect Mask 2D` component attached to the container's GameObject.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"60%\" src=\"https://user-images.githubusercontent.com/47441314/137837996-42eacaae-8852-40f4-acfd-41f8bf9110a3.png\"\u003e\n\u003c/p\u003e\n\n#### Get information about playing animation information\nYou can get the information about the transition animation currently playing from the following properties of the `Page`, `Modal`, `Sheet` classes.\n\n| Property Name | Description |\n|-|-|\n| IsTransitioning | Whether in transition or not. |\n| TransitionAnimationType | Type of the transition animation. If not in transition, return null. |\n| TransitionAnimationProgress | Progress of the transition animation. |\n| TransitionAnimationProgressChanged | Event when the progress of the transition animation changes. |\n\n#### Use loaded Prefab instances when loading screens\nThe `PreloadedAssetLoaderObject` allows you to load preloaded prefab instances directly, instead of using Resources or Addressables when loading the screen.\nYou can use it by entering the key and prefab in the Scriptable Object created from Assets \u003e Create \u003e Resource Loader \u003e Preloaded Asset Loader as shown below.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"60%\" src=\"https://user-images.githubusercontent.com/47441314/174422762-5942a833-3a89-43bb-ab5f-a59eecaff1f6.png\"\u003e\n\u003c/p\u003e\n\nI also provide `PreloadedAssetLoader` implementation for runtime.\n\n## FAQ\n\n#### How to make each Screen with Scene instead of Prefab\nYou can load the Screen placed in the Scene by implementing `AssetLoader`.\nImplement `IAssetLoader` to load the Scene file that contains the requested screen and return the GameObject of the screen.\nSee [Change the loading method of screen resources](#change-the-loading-method-of-screen-resources) for details.\n\n#### How to separate view and logic\nI wrote the blog post below to demonstrate the concept and implementation.\n\nhttps://light11.hatenadiary.com/entry/2022/01/11/193925\n(Sorry but Japanese only)\n\n#### How to pass data to each screen\nFirst, as an example, data is passed to the screen when loading is completed in the demo scene, as shown below.\n\nhttps://github.com/Haruma-K/UnityScreenNavigator/blob/8a115b1b25ac1d9fcf4b1ab6d5f2c1cd1d915ee5/Assets/Demo/Scripts/CharacterModal.cs#L91\n\nHowever, there are many other possible ways to pass data.\nFor example, there may be a case where you want to use a DI Container to set data.\nTherefore, it is the policy of this library not to implement and enforce a specific way.\n\n#### How to reuse popped pages or modals\nPopped pages and modals are immediately destroyed and cannot be reused.\n\nThe essence of the desire for reuse can be categorized into the following two types.\n\n1. not wanting to load screen resources each time\n2. want to preserve the state of the screen\n\nOf these, the load time issue can be resolved by [Preloading](#preloading).\nAs for state preserving, from the standpoint of maintainability, state and view should be decoupled so that they can be reconstructed.\n\nIn addition, in general, from usability standpoint, it is \"Tab\" transition that should retain state.\nIn this library as well, the state is always preserved in transitions using \"Sheet\" to implement tabs.\nSee [Create sheet and transition](#create-sheet-and-transition) for details.\n\nAnd if reusable, users will need to manage the lifecycle by themselves. \nIn other words, when it is no longer needed, users must call the Cleanup method to destroy instance and clean up the memory.\n\n## License\nThis software is released under the MIT License.  \nYou are free to use it within the scope of the license.  \nHowever, the following copyright and license notices are required for use.\n\n* https://github.com/Haruma-K/UnityScreenNavigator/blob/master/LICENSE.md\n","funding_links":[],"categories":["Open Source Repositories","C\\#","C#"],"sub_categories":["Scene Transition"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FHaruma-K%2FUnityScreenNavigator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FHaruma-K%2FUnityScreenNavigator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FHaruma-K%2FUnityScreenNavigator/lists"}