はじめに

NativeScript(NativeScript-Vue) で ボトムタブバーによるナビゲーションを行う方法。

TL;DR

  • ボトムタブバーによるナビゲーションを行う方法を整理
  • TabView で実装する
  • もしくは BottomNavigation で実装可能

目次

  1. はじめに
  2. TL;DR
  3. 環境・条件
  4. 詳細
    1. TabView による実装
      1. 実装サンプル
      2. 表示イメージ
      3. 簡単な解説など
    2. BottomNavigation による実装
      1. 実装サンプル
      2. 表示イメージ
      3. 簡単な解説など
  5. まとめ
  6. 参考文献

環境・条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.15.3
BuildVersion: 19D76

$ node -v
v12.7.0

$ npm -v
6.10.3

$ tns --version
6.4.0

$ grep -C1 version package.json
"tns-ios": {
"version": "6.4.1"
},
"tns-android": {
"version": "6.4.1"
}

$ tns plugin
Dependencies:
┌──────────────────────────────┬─────────┐
│ Plugin │ Version │
│ @nativescript/theme │ ^2.2.1 │
│ @vue/devtools │ ^5.0.6 │
│ nativescript-socketio │ ^3.2.1 │
│ nativescript-toasty │ ^1.3.0 │
│ nativescript-vue │ ^2.4.0 │
│ nativescript-vue-devtools │ ^1.2.0 │
│ tns-core-modules │ ^6.0.0 │
│ vue-router │ ^3.1.5 │
└──────────────────────────────┴─────────┘
Dev Dependencies:
┌────────────────────────────────────┬─────────┐
│ Plugin │ Version │
│ @babel/core │ ^7.0.0 │
│ @babel/preset-env │ ^7.0.0 │
│ babel-loader │ ^8.0.2 │
│ nativescript-dev-webpack │ ^1.0.0 │
│ nativescript-vue-template-compiler │ ^2.0.0 │
│ nativescript-worker-loader │ ~0.9.0 │
│ node-sass │ ^4.9.2 │
│ vue-loader │ ^15.4.0 │
└────────────────────────────────────┴─────────┘
  • iPhone 11 Pro: iOS 13.3
  • Android HUAWEI nova lite 2: Android 9 (ビルド 9.1.0.160)

詳細

TabView、もしくは BottomNavigation で実装可能。

リポジトリ: 17number/nativescript-vue-tutorial

参考コミット:

TabView による実装

実装サンプル

TabView を使う場合のサンプルコード。
参考コミット: @24cde8b

Android は androidTabsPosition="bottom" を指定する(指定なしだとトップに配置されるので注意)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<!-- app/tabs/BottomTab.vue -->
<template>
<Page>
<ActionBar :title="title">
<NavigationButton text="Back" android.systemIcon="ic_menu_back" @tap="back"/>
</ActionBar>
<TabView :selectedIndex="selectedIndex" @selectedIndexChange="onIndexChange" androidTabsPosition="bottom">
<TabViewItem title="Tab 1">
<FirstTab/> <!-- コンテンツ部分  -->
</TabViewItem>
<TabViewItem title="Tab 2">
<SecondTab/>
</TabViewItem>
<TabViewItem title="Tab 3">
<ThirdTab/>
</TabViewItem>
</TabView>
</Page>
</template>

<script >
import FirstTab from '@/tabs/FirstTab.vue'
import SecondTab from '@/tabs/SecondTab.vue'
import ThirdTab from '@/tabs/ThirdTab.vue'

export default {
components: {
FirstTab,
SecondTab,
ThirdTab,
},
data() {
return {
selectedIndex: 0,
title: 'Tab sample',
};
},
methods: {
back() {
this.$navigateBack({
transitionAndroid: { name: 'slide '},
});
},
onIndexChange(args) {
this.selectedIndex = args.value;
this.title = `Tab sample - ${this.selectedIndex + 1}`;
},
},
}
</script>

コンテンツ部分。今回は別ファイルにしているが、↑ の TabViewItem 内に直接記述していっても可。
※ファイル分割や配置はまだよくわかってない。(app/tabs or app/pages/tabs or app/components/tabs のどこが良いのか…)

1
2
3
4
5
6
7
8
9
10
<!-- app/tabs/FirstTab.vue -->
<template>
<StackLayout>
<Label text="1st tab content" textWrap="true" />
</StackLayout>
</template>

<script >
export default {}
</script>

表示イメージ

iOS

Android

Android(androidTabsPosition="bottom" 無し)

簡単な解説など

args.value に選択したタブの index, args.oldValue に前のタブの index が設定されている。

1
2
3
4
5
6
7
8
9
10
export default {
...
methods: {
...
onIndexChange(args) {
this.selectedIndex = args.value;
...
},
},
}

以下のように TabViewItem の下で ActionBar を指定するようなことはできない。タブごとに変更したい場合はイベントハンドラの中で処理する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<TabViewItem title="Tab 1">
<!-- ↓ は NG -->
<ActionBar title="Tab 1 selected">
<Label text="Content for Tab 1" />
</TabViewItem>

<script>
export default {
...
methods: {
...
onIndexChange(args) {
// イベントハンドラ内で変更
this.title = `Tab ${this.selectedIndex + 1} selected`;
...
},
},
}
</script>

アイコンを設定したい場合は以下のように iconSource で設定する。

1
2
3
<TabViewItem title="Tab 1" iconSource="~/images/icon.png">
<Label text="Content for Tab 1" />
</TabViewItem>

色変更は tabTextColor, tabBackgroundColor, tabBackgroundColor などで可能、詳細は Styling - TabView - NativeScript DocsClass TabView | NativeScript を参照

BottomNavigation による実装

NatvieScript-Vue のドキュメントには記載がないが、BottomNavigation でも実現可能。

実装サンプル

参考コミット: @33ef36e

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<template>
<Page>
<ActionBar :title="title">
<NavigationButton text="Back" android.systemIcon="ic_menu_back" @tap="back" />
</ActionBar>
<BottomNavigation :selectedIndex="selectedIndex" @selectedIndexChanged="onIndexChange">
<!-- ボトムタブバーの表示内容 -->
<TabStrip>
<TabStripItem>
<Label text="Home"/>
<Image src="font://&#xf015;"/>
</TabStripItem>

<TabStripItem class="special">
<Label text="Account"/>
<Image src="font://&#xf007;"/>
</TabStripItem>

<!-- Shorthand: title, iconSource で Label, Image を指定したのと同じ結果になる -->
<TabStripItem title="Search" iconSource="font://&#xf00e;"/>
</TabStrip>

<!-- タブごとのコンテンツ -->
<TabContentItem>
<FirstTab />
</TabContentItem>
<TabContentItem>
<SecondTab />
</TabContentItem>
<TabContentItem>
<ThirdTab />
</TabContentItem>
</BottomNavigation>
</Page>
</template>

<script >
import FirstTab from '@/tabs/FirstTab.vue'
import SecondTab from '@/tabs/SecondTab.vue'
import ThirdTab from '@/tabs/ThirdTab.vue'

export default {
components: {
FirstTab,
SecondTab,
ThirdTab,
},
data() {
return {
selectedIndex: 0,
title: 'Tab sample',
};
},
methods: {
back() {
this.$navigateBack({
transitionAndroid: { name: 'slide '},
});
},
onIndexChange(args) {
this.selectedIndex = args.newIndex;
this.title = `Tab sample - ${this.selectedIndex + 1}`;
},
},
}
</script>

表示イメージ

微妙に見た目が異なるが、CSS でどうにでも変更できると思われる。

iOS

Android

簡単な解説など

args.newIndex に現在のタブの index, args.oldIndex に前のタブの index が設定されている。

1
2
3
4
onIndexChange(args) {
this.selectedIndex = args.newIndex;
...
},

ActionBar については TabView と同様、必要に応じてイベントハンドラ内で変更する。

BottomNavigation の場合、メニュー部分とコンテンツ部分は別々に記載する。

メニュー部分は TabStrip 内に TabStripItem で定義。

1
2
3
4
5
6
7
8
9
10
<TabStrip>
<TabStripItem>
<Label text="tab 1"/>
<Image src="..."/>
</TabStripItem>
<TabStripItem>
<Label text="tab 2"/>
<Image src="..."/>
</TabStripItem>
</TabStrip>

上記はショートハンドで以下のようにも書ける。

1
2
3
4
<TabStrip>
<TabStripItem title="tab 1" iconSource="..."/>
<TabStripItem title="tab 2" iconSource="..."/>
</TabStrip>

コンテンツは TabContentItem で定義。

1
2
3
4
5
6
<TabContentItem>
<Label text="content 1" />
</TabContentItem>
<TabContentItem>
<Label text="content 2" />
</TabContentItem>

その他詳細は BottomNavigation - NativeScript DocsClass BottomNavigation | NativeScript を参照

まとめ

  • ボトムタブバーによるナビゲーションを行う方法を整理
  • TabView で実装する
  • もしくは BottomNavigation で実装可能

参考文献

関連記事