Following the sidebar APP in the previous article, this time we will add the upper and lower Tab pages to the APP to make it close to the mainstream information layout routine of most apps. If you can’t wait to see the source code, you can click into my Git repository to download the code.

Tab Key Elements

  • TabControllerThis is aTabPage controller for the definitionTabTAB and content page coordinates, also can configure the TAB page switch animation effect.

TabController is generally used in stateful controls to adapt to the scene where the number and content of TAB pages change dynamically. If the TAB pages are statically fixed in the APP, a simple version of DefaultTabController can be added to the stateless controls to improve the running efficiency. After all, stateless controls save more resources and run faster than stateful controls.

  • TabBar Tab page Title control, switch Tab page entrance, generally put under the AppBar control, internal has **Title* property. The child elements are arranged horizontally and horizontally. If you want to arrange vertically, wrap them with the Column or ListView control. An array of Tab children.

  • TabBarView Content container for a Tab page that holds the body content of the Tab page. Child elements can be multiple controls of various types.

Tab usage

Stateful control collocationTabController

Tab page switching with animation, therefore to the State class a SingleTickerProviderStateMixin added:

Class HomePage extends StatefulWidget {@override _HomePageState createState() => new _HomePageState(); } // Use a little bit of animation, Therefore joined the SingleTickerProviderStateMixin class _HomePageState extends the State < HomePage > with SingleTickerProviderStateMixin { . }Copy the code

Then initialize the TabController in the State subclass of the stateful control:

@override void initState() { super.initState(); _tabController = new TabController(vsync: this, length: 3 // TabController = new TabController(vsync: this, length: 3 // TabController = new TabController); Override void dispose() {_tabController.dispose (); super.dispose(); }Copy the code

Then call controller _tabController from the Controller property in TabBar and TabBarView

New Tab(icon: new icon (Icons. Directions_car)), new Tab(icon: new Icon(Icons.directions_transit)), new Tab(icon: New Icon(Icons. Directions_bike)),] // [ new Icon(Icons.directions_car), new Icon(Icons.directions_transit), new Icon(Icons.directions_bike), ]Copy the code

Finally, we place the TabBar and TabBarView definitions where they are needed, for example:

new Scaffold( appBar: new AppBar( backgroundColor: Colors.deepOrange, title: new Text('title'), ), .... Body: new TabBarView(//TabBarView renders content, so put the Scaffold body controller: _bottomNavigation, // configures controller children: New TabPage2(), new TabPage3(),]), bottomNavigationBar: Color: Colors. DeepOrange, // Bottom navigation bar theme color child: New TabBar(// the bottom navigation is placed in the bottomNavigationBar of the Scaffold. Controller: _bottomNavigation, // configure controller tabs: _bottomTabs, indicatorColor: Colors. White, // TAB label underline color),);Copy the code

Stateless control collocationDefaultTabController

DefaultTabController is much simpler. Since it is used in stateless controls, using DefaultTabController to wrap the page with a Tab is enough:

class TabPage3 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return  new DefaultTabController(
        length: 3,
        child: new Scaffold(
          appBar: new AppBar(
            backgroundColor: Colors.orangeAccent,
            title: new TabBar(
              tabs: [
                new Tab(icon: new Icon(Icons.directions_car)),
                new Tab(icon: new Icon(Icons.directions_transit)),
                new Tab(icon: new Icon(Icons.directions_bike)),
              ],
              indicatorColor: Colors.white,
            ),
          ),
          body: new TabBarView(
            children: [
              new Icon(Icons.directions_car),
              new Icon(Icons.directions_transit),
              new Icon(Icons.directions_bike),
            ],
          ),
        ),
      );
  }
}
Copy the code

The difference between DefaultTabController and TabController is mainly in the definition of the controller. TabBar and TabBarView are used in the same way. Normally the upper and lower Tab tags are placed on the appBar and bottomNavigationBar properties of the Scaffold control respectively. Then we fill APP with the following style:

The code structure

As shown in the figure above, the navigation bar at the bottom of the APP is the main entrance, and each Tab at the bottom has its own top secondary Tab page, so let’s tidy up the code structure:

  • _HomePageState is a subclass of APP HomePageState

  • The TabBar is placed through the bottomNavigationBar property at the bottom of the Scaffold to build the Tab bar of the Tab page

  • The body property of that Scaffold is put into TabBarView, whose children are the control pages defined by the three external DART files

  • The control pages defined by the external DART file have their own style tabs

  • The general properties of the Tab page can be pre-defined in the array List. Creating child elements in TabBar and TabBarView by iterating through the values of the List can improve code maintenance efficiency:

    Final List myTabs = [new Tab(text: ‘Tab1’), new Tab(text: ‘Tab1’) ‘Tab2’), new Tab(text: ‘Tab3’), new Tab(text: ‘Tab4’), new Tab(text: ‘Tab5’), new Tab(text: ‘Tab6’), new Tab(text: ‘Tab7’), new Tab(text: ‘Tab8’), new Tab(text: ‘Tab9’), new Tab(text: ‘Tab10’), new Tab(text: ‘Tab11’), ];

    Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( backgroundColor: OrangeAccent, title: new TabBar(Controller: _tabController, tabs: myTabs, // Colors.white, isScrollable: true, ), ), body: new TabBarView( controller: _tabController, children: MyTabs. Map ((Tab Tab) {// Iterate over List<Tab> myTabs and extract their property values as the contents of the child control return new Center(child: new Text(tab.text+' '+widget.data)); }).tolist (),),); }Copy the code

Use the obtained parameters

Due to the different page builds of StatelessWidget and StatefulWidget, there are slight differences in how parameters obtained from the outside are used, which is summarized here.

  • When defining the StatelessWidget as an argument or as an argument, add a variable of final type, such as pageText, to reserve space for parameter values and add parameter values to the constructor:

    class SidebarPage extends StatelessWidget { final String pageText; SidebarPage(this.pagetext); SidebarPage(this.pagetext); // The constructor gets the argument… }

When using a parameter, simply reference it:

Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar(title: Body: new Center(Child: new Text('pageText'),),); }Copy the code

When passing arguments from the outside, we simply fill the constructor with the values of the arguments:

Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new SidebarPage('First Page'))); // The control's constructor is called when the new method is passed in parameter valuesCopy the code
  • The way to get and use a StatefulWidget is slightly more complex than the way to use a StatelessWidget. When you define a constructor, you declare the key by default:

    class TabPage1 extends StatefulWidget { const TabPage1({ Key key , this.data}) : super(key: key); // Add final String data to the constructor; @override _MyTabbedPageState createState() => new _MyTabbedPageState(); }

When used, the State subclass needs to add a ***widget** in front of the parameter name because it implements specific page content in the State subclass.

class _MyTabbedPageState extends State<TabPage1> { ... new Center(child: new Text(tab.text+' '+widget.data)); // To use parameter values, add widget prefix before parameter names... }Copy the code

When passing in a parameter from the outside, declare the parameter name:

new TabBarView controller: _bottomNavigation, children: [ new TabPage1(data: // New TabPage2(), new TabPage3(),])Copy the code

Good le, today is here, we go to download my Git source code to try the effect, the code has additional notes, the characteristics of some control properties also have a separate description, I believe that after reading the source code, we can also achieve their own effect.

By the way, I would like to share a minefield. When I created this project, I used the command **flutter create [APPname1] to create this project, but I found that the APPname1 didn’t sound good and wanted to change the name to APPname2. So what do YOU do with android? “, renamed the project folder APPname2, and arbitrarily changed the _android\app\ SRC \main\ androidmanifest.xml_ file in the project directory, changing package and Android :label to APPname2. After the configuration was restored, the APP could not be started. Even if I tried to search for the full text of flutter fun, I could replace it with APPname2 or reverse it, but the APP could not be started. At this time, it was already 1am… No problem with the history of blood and tears, so solemnly warning everyone:

Do not easily change the project name in the various configuration files of the project! Do not easily change the project name in the various configuration files of the project! Do not easily change the project name in the various configuration files of the project! Otherwise you’re the next fish ball to beat your chest in front of the computer. What? How did I recover? Thanks to Git of course.

Thank you for your support. Please follow my Flutter circle and contribute to the Community of ** Flutter Chinese (official QQ group: 338252156) ** to grow together. Thank you