ナビゲーションとは、アプリケーションの画面内を移動することです。各モバイルアプリには、表示しようとする情報に基づいて独自のナビゲーションスキーマがあります。以下のスキーマは、一般的なモバイルナビゲーションシナリオの例です。
スキーマに基づいて、ユーザーが移動できる3つの異なる方向があります。
この記事では、これらをNativeScriptで実装し、それらを組み合わせてアプリケーションのナビゲーションアーキテクチャを構築する方法を示します。
ナビゲーション階層を下に移動しているため、前方ナビゲーションは下方ナビゲーションとも呼ばれます。 NativeScriptには、前方ナビゲーションの実装を可能にする2つのナビゲーションコンポーネント、FrameとPageがあります。 Frameは、Pageインスタンスをナビゲートするナビゲーションコントローラーを表します。
PageはNativeScriptの最も基本的なナビゲーション・コンポーネントです。 これは、ユーザーがナビゲートできる画面を表します。 このコンポーネントは、単一画面のUIコンポーネントを保持し、ナビゲーションライフサイクルイベントを提供するという、2つの重要な役割を果たします。 Pageコンポーネントに関する完全な情報については、専用の記事を参照してください。
設計上、Pageは別のコンポーネントの子として宣言することはでず、モジュールのルートコンポーネントとして使用されます。 その場合、モジュールはページモジュールになります。上の図のitem-pageモジュールを実装する方法の例を次に示します。
<Page loaded="onPageLoaded">
<ActionBar title="Item" class="action-bar"></ActionBar>
<StackLayout>
<Label text="Item Details"/>
</StackLayout>
</Page>
function onPageLoaded(args) {
console.log("Page Loaded");
}
exports.onPageLoaded = onPageLoaded;
import { EventData } from "tns-core-modules/data/observable";
export function onPageLoaded(args: EventData): void {
console.log("Page Loaded");
}
Pageを画面にを表示するには、Frameコンポーネントを使用してナビゲートする必要があります。 このコンポーネントは、NativeScriptの前方および後方ナビゲーションのメインプロバイダーです。 Frameコンポーネントは可視表現を有していません。 それは単にページ間の遷移のためのコンテナを提供します。 また、履歴操作やカスタムナビゲーション遷移の設定を含むナビゲーションAPIも提供します。 FrameコンポーネントとそのAPIの詳細については、こちらの記事を参照してください。
最も基本的なフォワードナビゲーションシナリオでは、次の2つの機能のみが必要です。
次の例は、上記の前方ナビゲーション図の残りの実装を示しています。 app-rootモジュールのルートコンポーネントとして宣言されたFrameがあります。 ロード時に、Frameは自動的に featured-pageモジュールに移動します。 featured-pageモジュールには、item-pageモジュールに移動するボタンがあります。 コードサンプルの下にある完全なプレイグラウンドデモをご覧ください。
<Frame id="featured" defaultPage="featured-page" />
<Page>
<ActionBar title="Featured" class="action-bar"></ActionBar>
<StackLayout>
<Button text="navigate('item-page')" tap="onTap"/>
</StackLayout>
</Page>
function onTap(args) {
const button = args.object;
const page = button.page;
page.frame.navigate("item-page");
}
exports.onTap = onTap;
import { EventData } from "tns-core-modules/data/observable";
import { Button } from "tns-core-modules/ui/button";
import { Page } from "tns-core-modules/ui/page";
export function onTap(args: EventData) {
const button: Button = <Button>args.object;
const page: Page = button.page;
page.frame.navigate("item-page");
}
これは、ナビゲーション階層を上に移動しているため、上向きナビゲーションとも呼ばれます。 このタイプのナビゲーションは、前方ナビゲーションの反対方向を表し、FrameAPI によってサポートされています。 Frameに読み込まれた前のページモジュールへのナビゲーションを強制するには、 単にgoBack()メソッドを呼び出します。 コードサンプルの下にある完全なプレイグラウンドデモをご覧ください。
<Page loaded="onPageLoaded">
<ActionBar title="Item" class="action-bar"></ActionBar>
<StackLayout>
<Label text="Item Details"/>
<Button text="goBack()" tap="onTap"/>
</StackLayout>
</Page>
function onPageLoaded(args) {
console.log("Page Loaded");
}
function onTap(args) {
const button = args.object;
const page = button.page;
page.frame.goBack();
}
exports.onTap = onTap;
exports.onPageLoaded = onPageLoaded;
import { EventData } from "tns-core-modules/data/observable";
import { Button } from "tns-core-modules/ui/button";
import { Page } from "tns-core-modules/ui/page";
export function onPageLoaded(args: EventData): void {
console.log("Page Loaded");
}
export function onTap(args: EventData) {
const button: Button = <Button>args.object;
const page: Page = button.page;
page.frame.goBack();
}
NativeScriptでラテラルナビゲーションを実装することは、通常、ナビゲーションにFrameコンポーネントの複数のインスタンスを組み込み、ユーザーにそれらを切り替える手段を提供することを意味します。 これは通常、特定のナビゲーションコンポーネントを介して有効になります。 これらには、BottomNavigation、Tabs、TabView、SideDrawer、Modal View、Frameが含まれ、それぞれが独自のモバイルナビゲーションパターンを提供します。
横方向のナビゲーションを実装する最も単純で簡単な方法は、ハブナビゲーションパターンです。 ハブと呼ばれる画面で構成され、さまざまな機能につながるナビゲーションボタンがあります。 本質的に、このパターンは、横方向のナビゲーションに順方向ナビゲーションの同じメカニズムを使用します。 NativeScriptでは、これをFrameで実装し、1つのPageをハブ画面として機能させることができます。
<Page class="page">
<ActionBar title="Hub" class="action-bar">
</ActionBar>
<StackLayout>
<Button text="navigate('featured-page')" tap="navigateToFeatured" />
<Button text="navigate('browse-page')" tap="navigateToBrowse" />
<Button text="navigate('search-page')" tap="navigateToSearch" />
</StackLayout>
</Page>
function navigateToFeatured(args) {
const button = args.object;
const page = button.page;
page.frame.navigate("featured-page");
}
function navigateToBrowse(args: EventData) {
const button = args.object;
const page = button.page;
page.frame.navigate("browse-page");
}
function navigateToSearch(args: EventData) {
const button = args.object;
const page = button.page;
page.frame.navigate("search-page");
}
exports.navigateToFeatured = navigateToFeatured;
exports.navigateToBrowse = navigateToBrowse;
exports.navigateToSearch = navigateToSearch;
import { EventData } from "tns-core-modules/data/observable";
import { Button } from "tns-core-modules/ui/button";
import { Page } from "tns-core-modules/ui/page";
export function navigateToFeatured(args: EventData) {
const button: Button =
BottomNavigationそしてtabsコンポーネントは、任意に同じレベルでいくつかのUI容器間を移動することを可能にします。 このコンポーネントの重要な機能は、表示されていないコンテナの状態を保持することです。 これは、ユーザーが前のタブに戻ったときに、データ、スクロール位置、およびナビゲーション状態が元のタブのままになっていることを意味します。 ナビゲーションスキーマをBottomNavigationまたはTabで実装する方法を示す図を次に示します。
BottomNavigationコンテナは、選択可能なタブをユーザーに提供することにより、その横方向のナビゲーションロジックを自動的に提供します。 BottomNavigationを設定するには、各コンテナのUI(TabContentItem内)と、 表示するタイトルとアイコン(TabStripItem内)を単に宣言する必要があります。 個別のUIコンテナーはそれぞれTabContentItemで表されます。 TabContentItemには1つのルートコンポーネントを含めることができます。 他のコンテナと同様に、各TabContentItemにFrameを埋め込むことで、TabContentItem内で前後のナビゲーションを有効にできます。
BottomNavigationは、横のナビゲーションに接続された2つの重要な機能を提供します。
コンポーネントの使用方法とカスタマイズ方法の詳細については、BottomNavigationの記事を参照してください。
上記の図に一致するBottomNavigation宣言のコードサンプルを次に示します。コードサンプルの下にある完全なプレイグラウンドデモを参照してください。
<BottomNavigation id="bottomNav" automationText="tabNavigation" selectedIndex="0" selectedIndexChanged="onSelectedIndexChanged">
<TabStrip>
<TabStripItem>
<Image src="font://" class="fas"></Image>
<Label text="Featured"></Label>
</TabStripItem>
<TabStripItem>
<Image src="font://󲴡" class="fas"></Image>
<Label text="Browse"></Label>
</TabStripItem>
<TabStripItem>
<Image src="font://" class="fab"></Image>
<Label text="Search"></Label>
</TabStripItem>
</TabStrip>
<TabContentItem>
<Frame id="featured" defaultPage="featured-page"></Frame>
</TabContentItem>
<TabContentItem>
<Frame id="browse" defaultPage="browse-page"></Frame>
</TabContentItem>
<TabContentItem>
<Frame id="search" defaultPage="search-page"></Frame>
</TabContentItem>
</BottomNavigation>
function onSelectedIndexChanged(args) {
console.log(`Selected index has changed ( Old index: ${args.oldIndex} New index: ${args.newIndex} )`);
}
exports.onSelectedIndexChanged = onSelectedIndexChanged;
import { SelectedIndexChangedEventData } from "tns-core-modules/ui/bottom-navigation";
export function onSelectedIndexChanged(args: SelectedIndexChangedEventData) {
console.log(`Selected index has changed ( Old index: ${args.oldIndex} New index: ${args.newIndex} )`);
}
新規Frameを全画面表示モーダルビューとして開くことは、非常に一般的なモバイルナビゲーションパターンです。 このコンテキストでは、モーダルビューを開くと、新しい機能への横方向のナビゲーションが表されます。 その後、埋め込みFrameを活用して、この機能で前後にナビゲートできます。 モーダルを閉じると、モーダルビューが開かれた場所に横方向に戻ります。 以下は、モーダルビューを使用してナビゲーションスキーマを実装する方法を示す図です。
NativeScriptの各UIコンポーネントは、モーダルビューを管理するための2つのメソッドを提供します。
モーダルビューを開くには、モーダルルートモジュールへのパスをパラメーターとして使用して、UIコンポーネントインスタンスのshowModal()メソッドを呼び出すだけです。 詳細については、モーダルビューの記事をご覧ください。
次のコードサンプルは、上の図の検索モーダルビューとページを実装する方法を示しています。コードサンプルの下にある完全なプレイグラウンドデモを参照してください。
<Frame id="featured" defaultPage="featured-page" />
<Page>
<ActionBar title="Featured" class="action-bar"></ActionBar>
<StackLayout>
<Button text="showModal('search-root', context, closeCallback, fullscreen)" tap="openSearchModal"/>
</StackLayout>
</Page>
function openSearchModal(args) {
const view = args.object;
const context = null;
const closeCallback = null;
const fullscreen = true;
view.showModal("search-root", context, closeCallback, fullscreen);
}
exports.openSearchModal = openSearchModal;
import { EventData } from "tns-core-modules/data/observable";
import { View } from "tns-core-modules/ui/core/view";
export function openSearchModal(args: EventData) {
const view: View = <View>args.object;
const context = null;
const closeCallback = null;
const fullscreen = true;
view.showModal("search-root", context, closeCallback, fullscreen);
}
<Frame id="search" defaultPage="search-page" />
<Page>
<ActionBar title="Search" class="action-bar"></ActionBar>
<StackLayout>
<Button text="closeModal()" tap="closeModal"/>
</StackLayout>
</Page>
function closeModal(args) {
const view = args.object;
view.closeModal();
}
exports.closeModal = closeModal;
import { EventData } from "tns-core-modules/data/observable";
import { View } from "tns-core-modules/ui/core/view";
export function closeModal(args: EventData) {
const view: View = <View>args.object;
view.closeModal();
}
このSideDrawerコンポーネントは、上級UIコンポーネントスイートの一部です。 ユーザーは、画面の両側からナビゲーションコントロールまたは設定を含む非表示のビュー、つまり引き出しを開くことができます。 SideDrawerを使用して実装できるナビゲーションパターンは次のとおりです。 一般的な使用方法は、UIコントロールを追加して、次の2つのいずれかを実行させることです。
実装できる最も単純なナビゲーションパターンはハブナビゲーションパターンですが、今回SideDrawerはハブとして機能します。
コンポーネント自体は、Tabsのようなナビゲーションロジックを自動的に提供しません。 代わりに、より自由に設計されており、コンテンツをカスタマイズできます。 これは、2つのUIコンテナーを公開します。drawerContentコンテナーは、非表示のサイドビューのUIを格納し、mainContentは、画面に表示されるUIを保持します。 上記の図を実装するために、メインコンテンツコンテナにFrameコンポーネントを埋め込むことができます。 この場合、ハブ画面は横に隠されるため、defaultPageプロパティを使用して最初にfeatured-pageのような機能の1つを表示する必要があります。 非表示の引き出しコンテンツには、3つのボタンがあります。それぞれが3つの機能のいずれかにナビゲートします。コードサンプルの下にある完全なプレイグラウンドデモを参照してください。
<nsDrawer:RadSideDrawer xmlns:nsDrawer="nativescript-ui-sidedrawer">
<nsDrawer:RadSideDrawer.drawerContent>
<StackLayout backgroundColor="gray">
<Button text="Featured" tap="navigateToFeatured" />
<Button text="Browse" tap="navigateToBrowse" />
<Button text="Search" tap="navigateToSearch" />
</StackLayout>
</nsDrawer:RadSideDrawer.drawerContent>
<nsDrawer:RadSideDrawer.mainContent>
<Frame id="root" defaultPage="featured-page" />
</nsDrawer:RadSideDrawer.mainContent>
</nsDrawer:RadSideDrawer>
const appModule = require("tns-core-modules/application");
const frameModule = require("tns-core-modules/ui/frame");
function navigateToFeatured(args) {
const sideDrawer = appModule.getRootView();
const featuredFrame = frameModule.getFrameById("root");
featuredFrame.navigate({
moduleName: "featured-page",
clearHistory: true
});
sideDrawer.closeDrawer();
}
function navigateToBrowse(args) {
const sideDrawer = appModule.getRootView();
const featuredFrame = frameModule.getFrameById("root");
featuredFrame.navigate({
moduleName: "browse-page",
clearHistory: true
});
sideDrawer.closeDrawer();
}
function navigateToSearch(args) {
const sideDrawer = appModule.getRootView();
const featuredFrame = frameModule.getFrameById("root");
featuredFrame.navigate({
moduleName: "search-page",
clearHistory: true
});
sideDrawer.closeDrawer();
}
exports.navigateToFeatured = navigateToFeatured;
exports.navigateToBrowse = navigateToBrowse;
exports.navigateToSearch = navigateToSearch;
import { RadSideDrawer } from "nativescript-ui-sidedrawer";
import { getRootView } from "tns-core-modules/application";
import { EventData } from "tns-core-modules/data/observable";
import { View } from "tns-core-modules/ui/core/view";
import { getFrameById } from "tns-core-modules/ui/frame";
export function navigateToFeatured(args: EventData) {
const sideDrawer: RadSideDrawer = <RadSideDrawer>getRootView();
const featuredFrame = getFrameById("root");
featuredFrame.navigate({
moduleName: "featured-page",
clearHistory: true
});
sideDrawer.closeDrawer();
}
export function navigateToBrowse(args: EventData) {
const sideDrawer: RadSideDrawer = <RadSideDrawer>getRootView();
const featuredFrame = getFrameById("root");
featuredFrame.navigate({
moduleName: "browse-page",
clearHistory: true
});
sideDrawer.closeDrawer();
}
export function navigateToSearch(args: EventData) {
const sideDrawer: RadSideDrawer = <RadSideDrawer>getRootView();
const featuredFrame = getFrameById("root");
featuredFrame.navigate({
moduleName: "search-page",
clearHistory: true
});
sideDrawer.closeDrawer();
}
SideDrawerの別のナビゲーションパターンは、メインコンテンツに1つの機能のみを保持させ、モーダルビューを使用して他の2つに横方向にナビゲートすることです。 完全な例については、コードサンプルの下のプレイグラウンドデモを参照してください。
<nsDrawer:RadSideDrawer xmlns:nsDrawer="nativescript-ui-sidedrawer">
<nsDrawer:RadSideDrawer.drawerContent>
<StackLayout>
<Label text="Featured" tap="resetFeatured" />
<Label text="Browse" tap="openBrowseModal" />
<Label text="Search" tap="openSearchModal" />
</StackLayout>
</nsDrawer:RadSideDrawer.drawerContent>
<nsDrawer:RadSideDrawer.mainContent>
<Frame id="featured" defaultPage="featured-page" />
</nsDrawer:RadSideDrawer.mainContent>
</nsDrawer:RadSideDrawer>
const appModule = require("tns-core-modules/application");
const frameModule = require("tns-core-modules/ui/frame");
function resetFeatured(args) {
const sideDrawer = appModule.getRootView();
const featuredFrame = frameModule.getFrameById("featured");
featuredFrame.navigate({
moduleName: "featured-page",
clearHistory: true
});
sideDrawer.closeDrawer();
}
function openBrowseModal(args) {
const sideDrawer = appModule.getRootView();
const view = args.object;
const context = null;
const closeCallback = null;
const fullscreen = true;
view.showModal("browse-root", context, closeCallback, fullscreen);
sideDrawer.closeDrawer();
}
function openSearchModal(args) {
const sideDrawer = appModule.getRootView();
const view = args.object;
const context = null;
const closeCallback = null;
const fullscreen = true;
view.showModal("search-root", context, closeCallback, fullscreen);
sideDrawer.closeDrawer();
}
exports.resetFeatured = resetFeatured;
exports.openBrowseModal = openBrowseModal;
exports.openSearchModal = openSearchModal;
import { RadSideDrawer } from "nativescript-ui-sidedrawer";
import { EventData } from "tns-core-modules/data/observable";
import { View } from "tns-core-modules/ui/core/view";
import { getFrameById } from "tns-core-modules/ui/frame";
export function resetFeatured(args: EventData) {
const sideDrawer: RadSideDrawer = <RadSideDrawer>getRootView();
const featuredFrame = getFrameById("featured");
featuredFrame.navigate({
moduleName: "featured-page",
clearHistory: true
});
sideDrawer.closeDrawer();
}
export function openBrowseModal(args: EventData) {
const sideDrawer: RadSideDrawer = <RadSideDrawer>getRootView();
const view: View = <View>args.object;
const context = null;
const closeCallback = null;
const fullscreen = true;
view.showModal("browse-root", null, null, true);
sideDrawer.closeDrawer();
}
export function openSearchModal(args: EventData) {
const sideDrawer: RadSideDrawer = <RadSideDrawer>getRootView();
const view: View = <View>args.object;
const context = null;
const closeCallback = null;
const fullscreen = true;
view.showModal("search-root", null, null, true);
sideDrawer.closeDrawer();
}
コンポーネントの詳細については、SideDrawerのドキュメントをご覧ください。