Skip to content

injected_tab_page_view_api

GIfatahTH edited this page Oct 2, 2021 · 1 revision

In Flutter to work with scrollable view, you use:

  • TabBarView, TabBar, TabController and DefaultTabController, or
  • PageView and pageController.

InjectedTabPageView state encapsulates the functionality of TabController and pageController to control tab and page views.

Table of Contents

InjectedTabPageView

InjectedTabPageView injectTabPageView({
  required int length,
  int initialIndex = 0,
  Duration duration = kTabScrollDuration,
  Curve curve = Curves.ease,
  bool keepPage = true,
  double viewportFraction = 1.0,
})
  • length: The number of tabs / pages to display. It can be dynamically changes later.
    // We start with 2 tabs
    final myInjectedTabPageView = RM.injectedTabPageView(length: 2);
    
    // Later on, we can extend or shrink the length of tab views.
    
    // Tab/page views are updated to display three views
    myInjectedTabPageView.length = 3
    
    // Tab/page views are updated to display one view
    myInjectedTabPageView.length = 1
  • initialIndex: The index of the tab / page to start with.
  • duration: The duration the tab / page transition takes.
  • curve: The duration the tab / page transition takes.
  • keepPage: Save the current page with PageStorage and restore it if this controller's scrollable is recreated. It works only for PageView not tabs
  • viewportFraction: The fraction of the viewport that each page should occupy. It works only for PageView not tabs

InjectedTabPageView exposes the following api:

  • tabController: get the associated TabController.
  • pageController: get the associated PageController.
  • index: get the current index of the active tab/page. When the index is set, The tab / page will animate to the target index.
  • length: get and dynamically set the length of views
  • previousIndex : The index of the previously selected tab / page.
  • indexIsChanging : True while we're animating from previousIndex to index as a consequence of calling animateTo.
  • animateTo method:
        void animateTo(
          int index, {
          Duration duration = kTabScrollDuration,
          Curve curve = Curves.ease,
        })
    Immediately sets index and previousIndex and then plays the animation from its current value to index.
  • nextView method:
        void nextView()
    Animates the controlled pages/tabs to the next page/tab
  • previousView method:
        void previousView()
    Animates the controlled pages/tabs to the previous page/tab

OnTabPageViewBuilder

To listen to an InjectedTabPageView, we use OnTabPageViewBuilder:

OnTabPageViewBuilder({
  // Optional, In most cases it can be omitted
  listenTo: myInjectedTabPageView,

  builder: (int currentIndex) {
      
      return TabView( ... )
  },
})

By default, OnTabPageBuilder deduces the InjectedTabPageView it must listen to. So listenTo parameter is optional.

The builder method exposes the currentIndex of the active tab / page.

Example

First we define our injectedTabPage

final injectedTabPage = RM.injectTabPageView(
  length: 3,
  //Optional
  initialIndex: 0,
  curve: Curves.ease,
  duration: Duration(milliseconds: 300),
  viewportFraction: 1.0,
  keepPage: true,
);

/// List of DataIcon to be used in pages an tabs
final icons = [
  Icons.directions_car,
  Icons.directions_transit,
  Icons.directions_bike,
  Icons.directions_boat,
  Icons.directions_bus_filled,
];

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        // Display the active index 
        title: OnReactive(
          () => Text(
            'Page ${injectedTabPage.index} is displayed',
          ),
        ),
        bottom: PreferredSize(
          preferredSize: Size(0, 40),
          child: Row(
            children: [
              IconButton(
                onPressed: () {
                  // Go to the previous view
                  injectedTabPage.previousView();
                },
                icon: Icon(Icons.arrow_back_ios_rounded),
              ),
              IconButton(
                onPressed: () {
                  // Go to the next view
                  injectedTabPage.nextView();
                },
                icon: Icon(Icons.arrow_forward_ios_rounded),
              ),
              Spacer(),
              IconButton(
                onPressed: () {
                  // Dynamically shrink the number of tabs / pages
                  if (injectedTabPage.length > 1) injectedTabPage.length--;
                },
                icon: Icon(Icons.cancel),
              ),
              IconButton(
                onPressed: () {
                  // Dynamically extend the number of tabs / pages
                  if (injectedTabPage.length < icons.length)
                    injectedTabPage.length++;
                  injectedTabPage.animateTo(injectedTabPage.length - 1);
                },
                icon: Icon(Icons.add_circle),
              ),
            ],
          ),
        ),
      ),
      // In the body and the bottomNavigationBar we can use Tabs only or pages only or use both.
      // The above code remains unchangeable.
      body: _body() ,
      bottomNavigationBar: _bottomNavigationBar(),
      ),
    );
  }
}

TabBarView controlled by TabBar

Here we use TabBarView and TabBar controlled by TabController.

Widget _body(){
    return OnTabPageViewBuilder(
        builder: (_) => TabBarView(
          controller: injectedTabPage.tabController,
          children: icons
              .getRange(0, injectedTabPage.length)
              .map((icon) => Icon(icon, size: 50))
              .toList(),
        ),
      )
}

Widget __bottomNavigationBar(){
    return OnTabPageViewBuilder(
        builder: (index) {
          return TabBar(
            controller: injectedTabPage.tabController,
            tabs: icons
              .getRange(0, injectedTabPage.length)
              .map((icon) => Icon(icon, color: Colors.blue))
              .toList(),
          );
        },
      ),
}

PageView controlled by with a list of OutlinedButton:

Here we use PageView controlled with a list of OutlinedButton.

Widget _body(){
    return OnTabPageViewBuilder(
        builder: (_) => PageView.builder(
          controller: injectedTabPage.pageController,
          itemCount: injectedTabPage.length,
          itemBuilder: (_, i) {
            return Icon(
              icons[i],
              size: 50,
            );
          },
        ),
      )
}

Widget __bottomNavigationBar(){
    return OnTabPageViewBuilder(
        listenTo: injectedTabPage,
        builder: (index) {
          return Row(
            children: icons
                .getRange(0, injectedTabPage.length)
                .toList()
                .asMap()
                .map((i, icon) {
                  return MapEntry(
                    i,
                    OutlinedButton(
                      onPressed: () => injectedTabPage.index = i,
                      child: Transform.scale(
                        scale: animate(i == index ? 1.2 : 0.8, '$i')!,
                        child: Icon(icon),
                      ),
                      style: OutlinedButton.styleFrom(
                        backgroundColor:
                            animate(i == index ? Colors.blue : null, '$i'),
                        primary: animate(
                            i != index ? Colors.blue : Colors.white,
                            'primary$i'),
                      ),
                    ),
                  );
                })
                .values
                .toList(),
            mainAxisAlignment: MainAxisAlignment.center,
          );
        },
      ),
}

PageView controlled by TabBar

Here we use PageView controlled by TabBar.

Widget _body(){
    return OnTabPageViewBuilder(
        builder: (_) => PageView.builder(
          controller: injectedTabPage.pageController,
          itemCount: injectedTabPage.length,
          itemBuilder: (_, i) {
            return Icon(
              icons[i],
              size: 50,
            );
          },
        ),
      )
}

Widget __bottomNavigationBar(){
    return OnTabPageViewBuilder(
        builder: (index) {
          return TabBar(
            controller: injectedTabPage.tabController,
            tabs: icons
              .getRange(0, injectedTabPage.length)
              .map((icon) => Icon(icon, color: Colors.blue))
              .toList(),
          );
        },
      ),
}

TabBarView controlled by BottomNavigationBar

Here we use PageView controlled by TabBar.

Widget _body(){
    return OnTabPageViewBuilder(
        builder: (_) => PageView.builder(
          controller: injectedTabPage.pageController,
          itemCount: injectedTabPage.length,
          itemBuilder: (_, i) {
            return Icon(
              icons[i],
              size: 50,
            );
          },
        ),
      )
}

Widget __bottomNavigationBar(){
    return OnTabPageViewBuilder(
        listenTo: injectedTabPage,
        builder: (index) {
          return BottomNavigationBar(
            currentIndex: index,
            onTap: (i)=> injectedTabPage.index = i,
            selectedItemColor: Colors.amber[800],
            tabs: icons
              .getRange(0, injectedTabPage.length)
              .map((icon) => 
                 BottomNavigationBarItem(
                     icon: Icon(icon),
                 ) 
               ,)
              .toList(),
          );
        },
      ),
}