Asynchronous screen transition/navigation for Unity.
NavStackはUnityにおける画面遷移を管理するためのライブラリです。非同期APIで構築された画面遷移の基盤インターフェースを提供するほか、uGUIとの連携やResources/Addressablesを用いたコンテンツ管理などをサポートします。
Note
現在NavStackはプレビュー版として公開されています。フィードバックをIssueやPull Requestでいただけると幸いです。
- Unity 2021.3 以上
- UniTask 2.0.0 以上
- Window > Package ManagerからPackage Managerを開く
- 「+」ボタン > Add package from git URL
- 以下のURLを入力する
https://github.com/AnnulusGames/NavStack.git?path=src/NavStack/Assets/NavStack
あるいはPackages/manifest.jsonを開き、dependenciesブロックに以下を追記
{
"dependencies": {
"com.annulusgames.navstack": "https://github.com/AnnulusGames/NavStack.git?path=src/NavStack/Assets/NavStack"
}
}NavStackにおいて、1つの画面は「Page」という単位に分割されます。Pageであるための要件はIPageインターフェースの実装のみであり、GameObjectやVisualElement、Sceneなど任意のものをPageとして表現することが可能です。
Pageの遷移やライフサイクルの管理は「Navigation」が行います。NavStackではPageの遷移履歴をスタック可能なINavigationStackと、履歴を持たずアクティブなPageの切り替えのみを行うINaviagtionSheetの2種類が用意されています。
Pageの基本インターフェースであるIPageは以下のような定義を持ちます。Pageの持つ各イベントはNavigation側から呼び出され、これを実装することによって画面遷移の処理をカスタマイズできます。
public interface IPage
{
UniTask OnNavigatedFrom(NavigationContext context, CancellationToken cancellationToken = default);
UniTask OnNavigatedTo(NavigationContext context, CancellationToken cancellationToken = default);
}| イベント | 説明 |
|---|---|
| OnNavigatedFrom | 他のPageへ遷移する際に呼ばれる。 |
| OnNavigatedTo | 他のPageから遷移してきた際に呼ばれる。 |
これをMonoBehaviourを継承したコンポーネント等で実装することでPageとして使用可能なViewを作成できます。
またIPageLifecycleEventを実装することで、Pageのライフサイクルイベントを追加することも可能です。
public interface IPageLifecycleEvent
{
UniTask OnAttached(CancellationToken cancellationToken = default);
UniTask OnDetached(CancellationToken cancellationToken = default);
}| イベント | 説明 |
|---|---|
| OnAttached | PageがNavigationに追加された際に呼ばれる。 |
| OnDetached | PageがNavigationから削除された際に呼ばれる。 |
NavigationStackはスタック形式の画面遷移をサポートするNavigationです。
NavigationStackではPushしたPageはスタックされ、最後にPushしたPageがアクティブなPageとして表示されます。PageをPushするにはPushAsync()、PopするにはPopAsync()を使用します。
INavigationStack navigationStack;
IPage page;
await navigationStack.PushAsync(page);
await navigationStack.PopAsync();また、Page側でIPageStackEventを実装することで、NavigationStack用のイベントを追加することも可能です。
public interface IPageStackEvent
{
UniTask OnPush(NavigationContext context, CancellationToken cancellationToken = default);
UniTask OnPop(NavigationContext context, CancellationToken cancellationToken = default);
}NavigationSheetはタブのような、アクティブなPageの切り替えをサポートするNavigationです。NavigationStackとは異なり、Pageの遷移履歴は保持されません。
NavigationSheetでは事前にAddAsync()でPageを追加する必要があります。
INavigationSheet navigationSheet;
IPage page1;
IPage page2;
IPage page3;
await navigationSheet.AddAsync(page1);
await navigationSheet.AddAsync(page2);
await navigationSheet.AddAsync(page3);表示するPageを切り替える際にはShowAsync()を呼び出します。また、Pageを非表示にしたい場合はHideAsync()を呼び出します。
int index = 0;
await navigationSheet.ShowAsync(index);
await navigationSheet.HideAsync();Pageを削除する際にはRemoveAsync()またはRemoveAllAsync()が利用できます。
await navigationSheet.RemoveAsync(page3);
await navigationSheet.RemoveAllAsync();Page間のデータの受け渡しやPage遷移のオプションの指定を行いたい場合、遷移時にNavigationContextを渡すことが可能です。
NavigationContextを通じて遷移先のPageにデータを渡すことが可能です。
var page = new ExamplePage();
var context = new NavigationContext()
{
Parameters = { { "id", "123456" } }
};
await navigationStack.PushAsync(page, context, cancellationToken);
class ExamplePage : IPage
{
public UniTask OnNavigatedTo(NavigationContext context, CancellationToken cancellationToken = default)
{
var id = (string)context.Parameters["id"];
...
}
...
}NavigationOptionsを渡すことで遷移のオプションを指定できます。(省略した場合にはNavigationのDefaultOptionsのオプションが適用されます。)
var context = new NavigationContext()
{
Options = new NavigationOptions()
{
Animated = true,
AwaitOperation = NavigationAwaitOperation.Drop,
}
};
await navigationStack.PushAsync(page, context, cancellationToken);| プロパティ | 説明 |
|---|---|
| Animated | 遷移アニメーションを再生するか (デフォルト値はtrue) |
| AwaitOpearion | Pageの遷移中に再び遷移処理が呼ばれた際の挙動を指定する (デフォルト値はNavigationAwaitOperation.Error) |
uGUIでNavStackを使用する際は、Canvas以下に配置した任意のオブジェクトにNavigation Stack / Navigation Sheet コンポーネントを追加します。
次に、UIを表示するためのPageを作成します。IPageクラスを実装したコンポーネントを定義しましょう。
public class SamplePage1 : MonoBehaviour, IPage
{
[SerializeField] CanvasGroup canvasGroup;
public async UniTask OnNavigatedTo(NavigationContext context, CancellationToken cancellationToken = default)
{
if (!context.Options.Animated)
{
canvasGroup.alpha = 1f;
return;
}
// この例ではLitMotionを用いたトゥイーンアニメーションを実装している
await LMotion.Create(0f, 1f, 0.25f)
.WithEase(Ease.InQuad)
.BindToCanvasGroupAlpha(canvasGroup)
.ToUniTask(CancellationTokenSource.CreateLinkedTokenSource(destroyCancellationToken, cancellationToken).Token);
}
public async UniTask OnNavigatedFrom(NavigationContext context, CancellationToken cancellationToken = default)
{
if (!context.Options.Animated)
{
canvasGroup.alpha = 0f;
return;
}
await LMotion.Create(1f, 0f, 0.25f)
.WithEase(Ease.OutQuad)
.BindToCanvasGroupAlpha(canvasGroup)
.ToUniTask(CancellationTokenSource.CreateLinkedTokenSource(destroyCancellationToken, cancellationToken).Token);
}
}また、作成したPageのオブジェクトはPrefabとして管理すると便利です。Prefab化したPageはPushNewObjectAsync()やAddNewObjectAsync()を用いてNavigationに追加することで、Pageのライフサイクルに基づいたオブジェクトの生成/破棄を行うことが可能です。
Page prefab;
NavigationStack navigationStack;
NavigationSheet navigationSheet;
await navigationStack.PushNewObjectAsync(prefab);
await navigationSheet.AddNewObjectAsync(prefab);TODO
TODO
TODO
