Tab View
The TabView component provides a simple way to
navigate between different views by tapping on some of the tabs
or by swiping between the views. By default the
TabView will load the view of the first tab,
however it's possible to load alternative tabs when the app
starts by setting the component’s
selectedIndex property.
const tabViewModule = require("tns-core-modules/ui/tab-view");
import { TabView, TabViewItem, SelectedIndexChangedEventData } from "tns-core-modules/ui/tab-view";
The general behavior of the TabView component is to
load its items on demand. This means that every
TabViewItem view will be loaded when it is shown
and will be unloaded when it disappears. Respectively, the
loaded and unloaded events will be
fired when navigating between views. However, there are some
specifics for each platform (iOS and Android), which are
described in the notes below.
Note (iOS specific): The iOS implementation uses
UITabBarController. This means that only oneTabViewItemcan be shown at a given time and only one needs to be loaded. When the user selects a newTabViewItem, we load the new item and unload the previous one.Note (Android specific): The Android implementation uses a
ViewPagercontrol, which allows using theswipegesture to navigate to the next or previous tab. This means that only oneTabViewItemcan be shown, but multipleTabViewItemsneed to be loaded to the side. If this is not done, you will not be able to see the nextTabViewItemcontents during the swipe. By default, theViewPagercontrol will pre-load oneTabViewItemon the left and on on the right. Regarding that, if one of the items is already pre-loaded, it will not be loaded again. In NativeScript, we have exposed a property calledandroidOffscreenTabLimit, which allows specifying how many components should be pre-loaded to the sides (if you are setting upandroidOffscreenTabLimitto 0, and using a nativescript version lower than 5, the Android behavior will match to the iOS behavior).
The iOS and Android UX guidelines regarding the Tab controls differ greatly. The difference is described in the below points:
- The iOS tabs have their tab bar, which will be displayed always on the bottom and does not allow swipe gesture for changing tabs.
- The Android tabs are on top and will enable the swipe navigation between the tabs.
-
For Android we have
androidTabsPositionproperty which has two optionstop(default value) andbottom. Setting up this property tobottomallows mimicking Bottom Tab Navigation control(provided by android support library v25 release). Setting the Tabs at the bottom will disable the swipe navigation and the items preloading functionality.
Basics
In a NativeScript application, TabView has an
items property which could be set via XML to an
array of TabViewItems (basically, an array of
objects with title, view and
iconSource properties). The following example shows
how to add a TabView to your page:
XML
<TabView id="tabViewContainer">
<TabViewItem title="First Tab" iconSource="res://icon">
<StackLayout>
<Label text="First Tab" textWrap="true" class="m-15 h2 text-left" color="blue" />
</StackLayout>
</TabViewItem>
<TabViewItem title="Second Tab" iconSource="res://icon">
<StackLayout>
<Label text="Second Tab" textWrap="true" class="m-15 h2 text-left" color="blue" />
</StackLayout>
</TabViewItem>
</TabView>
Note: If you have set the
iconSourceproperty on aTabViewItem, but are not seeing any icons next to the title, this might be because the icon is not present in your App_Resources folder. See the Working with Images article for information on how to add and reference your resource images.
Code Behind
This sample shows how to create TabView via
code-behind
// creating TabView Item content body
const stackLayout0 = new StackLayout();
const label0 = new Label();
label0.text = "Tab 0";
stackLayout0.addChild(label0);
const stackLayout1 = new StackLayout();
const label1 = new Label();
label1.text = "Tab 1";
stackLayout1.addChild(label1);
const tabViewItem0 = new tabViewModule.TabViewItem();
tabViewItem0.title = "Tab 0";
tabViewItem0.view = stackLayout0;
const tabViewItem1 = new tabViewModule.TabViewItem();
tabViewItem1.title = "Tab 1";
tabViewItem1.view = stackLayout1;
// creating TabView
const tabView = new tabViewModule.TabView();
// setting up its items and the selected index
const items = [];
items.push(tabViewItem0);
items.push(tabViewItem1);
tabView.items = items;
tabView.selectedIndex = 1;
// handling selectedIndexChangedEvent
tabView.on(tabViewModule.TabView.selectedIndexChangedEvent, (args) => {
dialogs.alert(`Selected index has changed ( Old index: ${args.oldIndex} New index: ${args.newIndex})`)
.then(() => {
console.log("Dialog closed!");
});
});
// creating TabView Item content body
const stackLayout0 = new StackLayout();
const label0 = new Label();
label0.text = "Tab 0";
stackLayout0.addChild(label0);
const stackLayout1 = new StackLayout();
const label1 = new Label();
label1.text = "Tab 1";
stackLayout1.addChild(label1);
const tabViewItem0 = new TabViewItem();
tabViewItem0.title = "Tab 0";
tabViewItem0.view = stackLayout0;
const tabViewItem1 = new TabViewItem();
tabViewItem1.title = "Tab 1";
tabViewItem1.view = stackLayout1;
// creating TabView
const tabView = new TabView();
// setting up its items and the selected index
const items = [];
items.push(tabViewItem0);
items.push(tabViewItem1);
tabView.items = items;
tabView.selectedIndex = 1;
// handling selectedIndexChangedEvent
tabView.on(TabView.selectedIndexChangedEvent, (argstv: SelectedIndexChangedEventData) => {
dialogs.alert(`Selected index has changed ( Old index: ${argstv.oldIndex} New index: ${argstv.newIndex})`)
.then(() => {
console.log("Dialog closed!");
});
});
Navigation
To navigate between the different TabViewItem views
programmatically, use the selectedIndex property.
You can also handle user input navigations with the
selectedIndexChanged event. The following example
displays the scenario in practice.
<TabView loaded="onLoaded" selectedIndex="{{tabSelectedIndex}}" selectedIndexChanged="onSelectedIndexChanged">
<TabViewItem title="Profile">
<StackLayout>
<Label text="{{ tabSelectedIndexResult }}" class="h2 m-t-16 text-center" textWrap="true" />
<Button text="Change Tab" tap="changeTab" class="btn btn-primary btn-active" />
</StackLayout>
</TabViewItem>
<TabViewItem title="Stats">
<StackLayout>
<Label text="{{ tabSelectedIndexResult }}" class="h2 m-t-16 text-center" textWrap="true" />
<Button text="Change Tab" tap="changeTab" class="btn btn-primary btn-active" />
</StackLayout>
</TabViewItem>
<TabViewItem title="Settings">
<StackLayout>
<Label text="{{ tabSelectedIndexResult }}" class="h2 m-t-16 text-center" textWrap="true" />
<Button text="Change Tab" tap="changeTab" class="btn btn-primary btn-active" />
</StackLayout>
</TabViewItem>
</TabView>
function onLoaded(args) {
const tabView = args.object;
const vm = new observableModule.Observable();
vm.set("tabSelectedIndex", 0);
vm.set("tabSelectedIndexResult", "Profile Tab (tabSelectedIndex = 0 )");
tabView.bindingContext = vm;
}
function changeTab(args) {
const vm = args.object.bindingContext;
const tabSelectedIndex = vm.get("tabSelectedIndex");
if (tabSelectedIndex === 0) {
vm.set("tabSelectedIndex", 1);
} else if (tabSelectedIndex === 1) {
vm.set("tabSelectedIndex", 2);
} else if (tabSelectedIndex === 2) {
vm.set("tabSelectedIndex", 0);
}
}
// displaying the old and new TabView selectedIndex
function onSelectedIndexChanged(args) {
if (args.oldIndex !== -1) {
const newIndex = args.newIndex;
const vm = args.object.bindingContext;
if (newIndex === 0) {
vm.set("tabSelectedIndexResult", "Profile Tab (tabSelectedIndex = 0 )");
} else if (newIndex === 1) {
vm.set("tabSelectedIndexResult", "Stats Tab (tabSelectedIndex = 1 )");
} else if (newIndex === 2) {
vm.set("tabSelectedIndexResult", "Settings Tab (tabSelectedIndex = 2 )");
}
dialogs.alert(`Selected index has changed ( Old index: ${args.oldIndex} New index: ${args.newIndex} )`)
.then(() => {
console.log("Dialog closed!");
});
}
}
exports.onLoaded = onLoaded;
exports.changeTab = changeTab;
exports.onSelectedIndexChanged = onSelectedIndexChanged;
export function onLoaded(args) {
const tabView: TabView = <TabView>args.object;
const vm = new Observable();
vm.set("tabSelectedIndex", 0);
vm.set("tabSelectedIndexResult", "Profile Tab (tabSelectedIndex = 0 )");
tabView.bindingContext = vm;
}
export function changeTab(args) {
const vm = args.object.bindingContext;
const tabSelectedIndex = vm.get("tabSelectedIndex");
if (tabSelectedIndex === 0) {
vm.set("tabSelectedIndex", 1);
} else if (tabSelectedIndex === 1) {
vm.set("tabSelectedIndex", 2);
} else if (tabSelectedIndex === 2) {
vm.set("tabSelectedIndex", 0);
}
}
// displaying the old and new TabView selectedIndex
export function onSelectedIndexChanged(args: SelectedIndexChangedEventData) {
if (args.oldIndex !== -1) {
const newIndex = args.newIndex;
const vm = (<TabView>args.object).bindingContext;
if (newIndex === 0) {
vm.set("tabSelectedIndexResult", "Profile Tab (tabSelectedIndex = 0 )");
} else if (newIndex === 1) {
vm.set("tabSelectedIndexResult", "Stats Tab (tabSelectedIndex = 1 )");
} else if (newIndex === 2) {
vm.set("tabSelectedIndexResult", "Settings Tab (tabSelectedIndex = 2 )");
}
dialogs.alert(`Selected index has changed ( Old index: ${args.oldIndex} New index: ${args.newIndex} )`)
.then(() => {
console.log("Dialog closed!");
});
}
}
Offscreen Tab Limit Android
Use the androidOffscreenTabLimit property to set
the number of pre-loaded side tabs on Android. The default value
is 1.
XML
<TabView id="tabViewContainer" androidOffscreenTabLimit="0">
<TabViewItem title="First Tab" iconSource="res://icon">
<StackLayout>
<Label text="First Tab" textWrap="true" class="m-15 h2 text-left" color="blue" />
</StackLayout>
</TabViewItem>
<TabViewItem title="Second Tab" iconSource="res://icon">
<StackLayout>
<Label text="Second Tab" textWrap="true" class="m-15 h2 text-left" color="blue" />
</StackLayout>
</TabViewItem>
</TabView>
Styling
The TabView component has the following unique
styling properties:
-
tabTextColor(corresponding CSS propertytab-text-color) - Changes the text color for the tabs. -
selectedTabTextColor(corresponding CSS propertyselected-tab-text-color) - Changes the color of the text for the selected tab. -
tabBackgroundColor(corresponding CSS propertytab-background-color) - Sets the background color of the tabs. -
tabTextFontSize(corresponding CSS propertytab-text-font-size) - Sets the font size of the tabs. -
textTransform(corresponding CSS propertytext-transform) - Sets the text transform individually for everyTabViewItem. Value options:capitalize,lowercase,none, anduppercase. -
androidSelectedTabHighlightColorandroid specific property (corresponding CSS propertyandroid-selected-tab-highlight-color) - Sets the underline color of the tabs in Android.
XML
<TabView selectedTabTextColor="white"
tabBackgroundColor="orangered"
tabTextFontSize="16"
androidSelectedTabHighlightColor="green">
<TabViewItem title="First tab" iconSource="res://icon" textTransform="capitalize">
<StackLayout>
<Label text="First Tab" textWrap="true" class="m-15 h2 text-center" color="blue" />
</StackLayout>
</TabViewItem>
<TabViewItem title="Second tab" iconSource="res://icon" textTransform="capitalize">
<StackLayout>
<Label text="Second Tab" textWrap="true" class="m-15 h2 text-center" color="blue" />
</StackLayout>
</TabViewItem>
</TabView>
Tabs Position Android
Use the androidTabsPosition property to change the
position of the tabs on Android. The default value is
top.
XML
<TabView id="tabViewContainer" androidTabsPosition="bottom">
<TabViewItem title="First Tab" iconSource="res://icon">
<StackLayout>
<Label text="First Tab" textWrap="true" class="m-15 h2 text-left" color="blue" />
</StackLayout>
</TabViewItem>
<TabViewItem title="Second Tab" iconSource="res://icon">
<StackLayout>
<Label text="Second Tab" textWrap="true" class="m-15 h2 text-left" color="blue" />
</StackLayout>
</TabViewItem>
</TabView>
Title Icon Fonts
The example demonstrates, how to use Icon font for the
TabView items title. For more information on how to
add and use Icon fonts in your app, refer to the
Icon Fonts article.
XML
<TabView id="tabViewContainer" class="icon">
<TabViewItem title="">
<StackLayout>
<Label text="First TabView item with Icon Font" textAlignment="center" textWrap="true" class="h2 m-x-auto" color="blue" />
<Label text="" textWrap="true" class="h2 m-x-auto" color="blue" />
</StackLayout>
</TabViewItem>
<TabViewItem title="">
<StackLayout>
<Label text="Second TabView item with Icon Font" textAlignment="center" textWrap="true" class="h2 m-x-auto" color="green" />
<Label text="" textWrap="true" class="h2 m-x-auto" color="green" />
</StackLayout>
</TabViewItem>
</TabView>
CSS
.icon{
font-family: 'icomoon';
}
API Reference for the TabView Class
Native Component
| Android | iOS |
|---|---|
| androidx.viewpager.widget.ViewPager | UITabBarController |