1
votes

I'm trying to implement a UI in my NativeScript app, where the app has 2 tabs, with each tab having a navigation stack of its own. A similar pattern is seen in some apps, such as the Photos app. Here is a demonstration:

enter image description here

Is that possible with NativeScript? With the following code (Angular 2), I end up with a single navigation bar shared across both tabs. Only the second one (title Nearby) is kept:

<TabView>
  <StackLayout *tabItem="{ title: 'Home' }">
    <ActionBar title="Home"></ActionBar>
    <mp-home></mp-home>
  </StackLayout>
  <StackLayout *tabItem="{ title: 'Nearby' }">
    <ActionBar title="Nearby"></ActionBar>
    <Label text="Placeholder for Nearby"></Label>
  </StackLayout>
</TabView>
2

2 Answers

0
votes

I discovered by looking at the source code of nativescript-angular that there is a SelectedIndexValueAccessor directive which adds support for ngModel to TabView components. It syncs the ngModel value to the selectedIndex for the tab, which means we can use the following code to update the ActionBar title property:

<TabView [(ngModel)]="selectedTabIndex">

  <ActionBar
   [title]="selectedTabIndex === 0 ? homeTab.title : nearbyTab.title">
  </ActionBar>

  <StackLayout *tabItem="homeTab">
    <mp-home></mp-home>
  </StackLayout>

  <StackLayout *tabItem="nearbyTab">
    <Label text="Placeholder for Nearby"></Label>
  </StackLayout>

</TabView>

That works, but it still means we only have a single ActionBar (iOS Navigation Bar). That's not ideal if you're trying to build a UI in which each tab has its own navigation stack, but from looking at the source code for the TabView component, it appears that it is how it works: every time a new TabView instance is created, the constructor of TabView replaces the instance of the actionBar on the topmost page object with itself.

For my app I'm going to make sure that the tab bar is only visible on the topmost page, which avoids the above being a problem.

0
votes

I wasn't able to make it work with SelectedIndexValueAccessor directive, so i adapted another solution, hope somebody finds it useful:

mainPage.html:

<ActionBar [title]="tabs[tabId].title" class="action-bar"></ActionBar>

<GridLayout>
    <TabView #tabview (selectedIndexChanged)="tabIndexChanged($event)">

      <StackLayout *tabItem="tabs[0]" >
          <first-tabview-item></first-tabview-item>
      </StackLayout>

      <StackLayout *tabItem="tabs[1]">
          <second-tabview-item></second-tabview-item>
      </StackLayout>

      <StackLayout *tabItem="tabs[2]">
          <third-tabview-item></third-tabview-item>
      </StackLayout>

    </TabView>
</GridLayout>

mainPage.component.ts:

import { Component, OnInit } from "@angular/core";

@Component({
    selector: "main-page",
    moduleId: module.id,
    templateUrl: "./mainPage.html",
    styleUrls: ["./mainPage-common.css", "./mainPage.css"],
})
export class MainPageComponent implements OnInit {
    private tabs: object[];
    private tabId: number;

    constructor() { }

    public ngOnInit(): void {

        this.tabs = [
            {
                title: 'Tab 1 title',
                iconSource: '~/images/tab1.png',
            },
            {
                title: 'Tab 2 title',
                iconSource: '~/images/tab2.png',
            },
            {
                title: 'Tab 3 title',
                iconSource: '~/images/tab3.png',
            },
        ];

    }

    public tabIndexChanged(event: any) {
        this.tabId = event.newIndex;
        console.log(`Selected tab index: ${event.newIndex}`);
    }
}