Flutter基礎(chǔ)(六)Material組件之BottomNavigationBar、TabBar、Drawer

每日一言:自信來自于內(nèi)心,而不是來自于和別人的比較,和別人比較永遠不可能帶來真正的自信。比較的結(jié)果不是產(chǎn)生虛妄的優(yōu)越感,就是產(chǎn)生強烈的自卑感。這兩種感覺和真實的你無關(guān),也和自信無關(guān)。自信是一種自我肯定,肯定自己在某些方面能夠做得比較出色,而不是在所有方面都比別人好。

原文鏈接:http://liuwangshu.cn/flutter/primer/6-material-components-2.html

前言

在上一篇 Flutter基礎(chǔ)(五)Material組件最佳入門(前篇)中,我介紹了Material組件的MaterialApp、Scaffold、AppBar,這篇文章接著介紹Material組件中的BottomNavigationBar、TabBar、Drawer。

1.BottomNavigationBar

BottomNavigationBar是底部的導航欄,用于在3到5個的少量視圖中進行選擇。一般情況下,導航欄的選項卡由文本標簽、圖標或兩者結(jié)合的形式組成。

底部導航欄通常與javaScaffold結(jié)合使用,它會作為Scaffold.bottomNavigationBar參數(shù)。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyStatefulWidget(),
    );
  }
}

class MyStatefulWidget extends StatefulWidget {
  MyStatefulWidget({Key key}) : super(key: key);

  @override
  _MyStatefulWidgetState createState() => _MyStatefulWidgetState();//1
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  int _selectedIndex = 0;
  static const List<Widget> _widget = <Widget>[
    Text(
      'Index 0:首頁',
    ),
    Text(
      'Index 1: 通訊錄',
    ),
    Text(
      'Index 2: 設(shè)置',
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('BottomNavigationBar示例'),
      ),
      body: Center(
        child: _widget.elementAt(_selectedIndex),
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            title: Text('首頁'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.contacts),
            title: Text('通訊錄'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.build),
            title: Text('設(shè)置'),
          ),
        ],
        currentIndex: _selectedIndex,
        selectedItemColor: Colors.amber,
        onTap: _onItemTapped, //2
      ),
    );
  }
  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }
}

由于使用的Widget需要在Widget的生命周期中改變狀態(tài),因此MyStatefulWidget繼承了StatefulWidget。注釋1處的createState方法會為此Widget創(chuàng)建可變狀態(tài)。注釋2處的onTap屬性會在點擊其中一個選項卡時調(diào)用,它的值由_onItemTapped方法定義,在這個方法中設(shè)置當前的索引賦值給_selectedIndex,這樣通過_selectedIndex的值就可以切換選項卡了。實現(xiàn)的效果如下所示,可以通過點擊選項卡來切換界面。

image

2.TabBar

TabBar用于顯示水平的選項卡,和Android中的TabLayout類似。TabBar通常需要配合TabBarView和TabController。其中TabBarView用于顯示與當前所選的選項卡對應(yīng)的Widget視圖;TabController顧名思義就是TabBarView和TabBar的控制器,是這兩個Widget的橋梁。實現(xiàn)TabController有兩種方式,一種是用系統(tǒng)的DefaultTabController,另一種是自定義TabController。

2.1 使用DefaultTabController

DefaultTabController這種方式方便快捷,直接新建一個DefaultTabController就可以了。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyTabController(),
    );
  }
}
class MyTabController extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 3,
      child: Scaffold(
        appBar: AppBar(
          title: Text('DefaultTabController示例'),
          bottom: TabBar(
            tabs: <Widget>[
              Tab(
                text: '熱點',
              ),
              Tab(
                text: '體育',
              ),
              Tab(
                text: '科技',
              ),
            ],
          ),
        ),
        body: TabBarView(
          children: <Widget>[
            Center(child: Text('熱點')),
            Center(child: Text('體育')),
            Center(child: Text('科技')),
          ],
        ),
      ),
    );
  }
}

2.2 自定義TabController

如果想要切換動畫或者監(jiān)聽切換的交互,可以自定義TabController,需要實現(xiàn)SingleTickerProviderStateMixin。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyStatefulWidget(),
    );
  }
}

class MyStatefulWidget extends StatefulWidget {
  MyStatefulWidget({Key key}) : super(key: key);
  @override
  _MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget>
    with SingleTickerProviderStateMixin {
  TabController _tabController;

  void initState() {
    super.initState();
    _tabController = TabController(vsync: this, length: 3);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('自定義TabController'),
        bottom: TabBar(
          tabs: <Widget>[
            Tab(
              text: '熱點',
            ),
            Tab(
              text: '體育',
            ),
            Tab(
              text: '科技',
            ),
          ],
          controller: _tabController,//1
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: <Widget>[
          Center(child: Text('熱點')),
          Center(child: Text('體育')),
          Center(child: Text('科技')),
        ],
      ),
    );
  }
  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }
}

和第一種使用DefaultTabController有兩點不同,一個是使用了StatefulWidget,另一個是在注釋1處將TabBar的controller設(shè)置為新建的TabController。運行效果如下所示,可以通過滑動界面和點擊選項卡來切換界面。

image

3.Drawer

Drawer就是抽屜,可以實現(xiàn)拉出推入的效果,和Android中的DrawerLayout類似。Drawer通常與Scaffold.drawer屬性一起使用,抽屜的子項通常是ListView,其第一個子項是頭部,頭部主要有兩個Widget可以實現(xiàn):

DrawerHeader:展示基本的信息

UserAccountsDrawerHeader:展示用戶頭像、用戶名、Email等信息。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyStatefulWidget(),
    );
  }
}

class MyStatefulWidget extends StatefulWidget {
  MyStatefulWidget({Key key}) : super(key: key);

  @override
  _DrawerState createState() => _DrawerState();
}

class _DrawerState extends State<MyStatefulWidget> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Drawer例子'),
      ),
      drawer: _drawer,
    );
  }
  get _drawer => Drawer(
        child: ListView(//1
          padding: EdgeInsets.zero,
          children: <Widget>[
            UserAccountsDrawerHeader(
              accountName: Text('乘香墨影'),
              accountEmail: Text('liuwangshu.gmail.com'),
              currentAccountPicture: CircleAvatar(
                child: Text('X'),
              ),
            ),
            ListTile(
              leading: Icon(Icons.local_post_office),
              title: Text('郵件'),
            ),
            ListTile(
              leading: Icon(Icons.settings),
              title: Text('設(shè)置'),
            )
          ],
        ),
      );
}

跟以往例子不同的是,由于drawer屬性的代碼比較多,為了提高可讀性,我將drawer屬性的值抽取出來,通過getter的形式進行獲取。注釋1處可以看出Drawer的子項為ListView,ListView的通過ListTile來顯示每一個列表項。注釋2使用的是UserAccountsDrawerHeader,可以很輕松的設(shè)置用戶的姓名、郵箱、用戶圖片等。效果如下圖所示:

image

總結(jié)

加上上一篇文章,我已經(jīng)介紹了Material組件中應(yīng)用程序結(jié)構(gòu)和導航分類中的大部分Widget,另外Material組件所包含的其他的Widget,本系列就不介紹了,想要了解的可以查看文檔:https://flutter.dev/docs/development/ui/widgets/material

后續(xù)還有更多精彩文章,大家請關(guān)注我的微信公眾號

image
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容