AngularDart - UI Componentのアニメーションを維持したままページ遷移する
やりたいことは以下の動画のとおり。
ページ遷移してURLは変わるが、アニメーションは維持する。
モチベーション
Routerでページ遷移すると、対応するComponentが新たに起動する。しかし、上記の動画のように、たとえばTabの遷移に合わせてURLを変更したい場合、Component instanceが新たに起動して状態が一新されると、UI上はアニメーションがぶつりと中断してしまい不格好なUIになってしまう。アニメーションを維持したままページ遷移したい。
ソリューション
Tab1 page, Tab2 pageに対応するpathに紐つけるPageのComponentを、同一のものにする。ここでは、ATabCyclePage
とする。
そして、Routerのlife cycle interfaceであるCanReuseを、Componentにimplementする。CanReuseは、Component instanceを再利用するかどうかを指定する。
class ATabCyclePage implements OnActivate, CanReuse { int activeTabIndex; @override void onActivate(RouterState previous, RouterState current) { activeTabIndex = _isTab1Page(current.path) ? 0 : 1; } @override Future<bool> canReuse(RouterState current, RouterState next) async { // Componentを再利用する条件を記述。たとえばcurrentとnextのpathを比較してUIのTab遷移に対応する状態ならばtrueを返す。 } }
Templateのサンプル
<material-tab-panel class="tab-panel" [activeTabIndex]="activeTabIndex" (tabChange)="handleTabChange($event)"> <material-tab label="Tab 1"> <template deferredContent> <ng-container *ngIf="activeTabIndex != null"> <material-button raised (trigger)="navigateToTab2Page()">click to Tab 2</material-button> </ng-container> </template> </material-tab> <material-tab label="Tab 2"> <template deferredContent> <!--Tab 2 Page--> </template> </material-tab> </material-tab-panel>
Tabが変わった際のハンドラ
void handleTabChange(TabChangeEvent event) { if (event.newIndex == 0) { _navigateToTab1Page(); } else if (event.newIndex == 1) { navigateToTab2Page(); } else { // throw } } void _navigateToTab1Page() => _router.navigate(RoutePaths.tab1 .toUrl(parameters: {'id': _router.current.parameters['id']})); void navigateToTab2Page() => _router.navigate(RoutePaths.tab2 .toUrl(parameters: {'id': _router.current.parameters['id']}));
これで、アニメーションを維持したままページ遷移が可能となった。