flutter實現底部Tab和頂部導航條切換

目錄

 

底部Tab:使用BottomNavigationBar來實現。

頂部Tab(DefaultTabController實現方式):

還有另一種實現方式:實現SingleTickerProviderStateMixin(適用於已確定要顯示Tab標籤)

如果是動態添加標籤,就需要實現TickerProviderStateMixin,注意:不是SingleTickerProviderStateMixin,接口請求結束後,在setState中仍需要再初始化一遍TabController

有些需求會要求實現某部分佈局滑到頂部後吸頂懸浮


底部Tab:使用BottomNavigationBar來實現。

class IndexPage extends StatefulWidget {
  @override
  _IndexPageState createState() => _IndexPageState();
}

class _IndexPageState extends State<IndexPage> {
  List<BottomNavigationBarItem> tabs = [
    BottomNavigationBarItem(
      icon: Image.asset("images/home_unactive.png", width: 24, height: 24),
      activeIcon: Image.asset("images/home_active.png", width: 24 height: 24),
      title: Text("首頁"),
    ),
    BottomNavigationBarItem(
      icon: Image.asset("images/home_unactive.png", width: 24, height: 24),
      activeIcon: Image.asset("images/home_active.png", width: 24 height: 24),
      title: Text("分類"),
    ),
    BottomNavigationBarItem(
      icon: Image.asset("images/home_unactive.png", width: 24, height: 24),
      activeIcon: Image.asset("images/home_active.png", width: 24 height: 24),
      title: Text("購物車"),
    ),
    BottomNavigationBarItem(
      icon: Image.asset("images/home_unactive.png", width: 24, height: 24),
      activeIcon: Image.asset("images/home_active.png", width: 24 height: 24),
      title: Text("我的"),
    ),
  ];

  List<Widget> pages = [
    HomePage(),
    CategoryPage(),
    ShoppingCartPage(),
    MyPage(),
  ];

  int currentIndex = 0;
  PageController _controller = PageController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: PageView(
        controller: _controller,
        children: pages,
        physics: NeverScrollableScrollPhysics(), //禁止頁面滾動
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: currentIndex,
        items: tabs,
        unselectedFontSize: 13,
        selectedFontSize: 13,
        type: BottomNavigationBarType.fixed,
        onTap: (index) {
          _controller.jumpToPage(index);
          setState(() {
            currentIndex = index;
          });
        },
      ),
    );
  }
}

頂部Tab(DefaultTabController實現方式):

body: DefaultTabController(
          length: 3,//項的數量
          initialIndex: 0,//默認選擇第一項
          child: Column(
            children: <Widget>[
              Container(
                color: Colors.lightBlue,
                child: AspectRatio(
                  aspectRatio: 8.0,
                  child: TabBar(
//                    isScrollable: true,//項少的話,無需滾動(自動均分屏幕寬度),多的話,設爲true
                    indicatorColor: Colors.red,
                    indicatorWeight: 2,
                    unselectedLabelColor: Colors.white,
                    labelColor: Colors.red,
                    tabs: [
                      Tab(
                        text: "科技",
                      ),
                      Tab(
                        text: "汽車",
                      ),
                      Tab(
                        text: "金融",
                      ),
                    ],
                  ),
                ),
              ),
              Expanded(
                child: TabBarView(
                  children: [
                    TechFragment(),
                    CarFragment(),
                    FinanceFragment(),
                  ],
                ),
              )
            ],
          ),
        ),

還有另一種實現方式:實現SingleTickerProviderStateMixin(適用於已確定要顯示Tab標籤)

initState中:

tabController = TabController(length: list.length, vsync: this);

如果是動態添加標籤,就需要實現TickerProviderStateMixin,注意:不是SingleTickerProviderStateMixin,接口請求結束後,在setState中仍需要再初始化一遍TabController

setState(() {
   tabController = TabController(length: list.length, vsync: this);
});

有些需求會要求實現某部分佈局滑到頂部後吸頂懸浮

可以是一個tabbar,也可以是一個別的組件,但是目的都是讓其吸頂懸浮在那,示例代碼如下:

import 'package:flutter/material.dart';

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: PreferredSize(
        child: AppBar(
          backgroundColor: Colors.red,
        ),
        preferredSize: Size.fromHeight(0),
      ),
      body: NestedScrollView(
        headerSliverBuilder: (_, innerBoxIsScrolled) {
          return [
            SliverToBoxAdapter(//其他內容用SliverToBoxAdapter包裹
              child: Container(
                height: 150,
                color: Colors.greenAccent,
                alignment: Alignment.center,
                child: Text(
                  "頭部",
                  style: TextStyle(
                    fontSize: 50,
                    color: Colors.white,
                  ),
                ),
              ),
            ),
            SliverPersistentHeader(//懸浮區
              pinned: true,
              delegate: _SliverAppBarDelegate(
                minHeight: 70,
                maxHeight: 70,
                child: Container(
                  child: Row(
                    children: <Widget>[
                      Expanded(
                        child: InkWell(
                          onTap: () {
                            print("Tab1");
                          },
                          child: Container(
                            alignment: Alignment.center,
                            child: Text("Tab1"),
                            color: Colors.red,
                          ),
                        ),
                      ),
                      Container(
                        width: 1,
                        height: 70,
                        color: Colors.white,
                      ),
                      Expanded(
                        child: InkWell(
                          onTap: () {
                            print("Tab2");
                          },
                          child: Container(
                            alignment: Alignment.center,
                            child: Text("Tab2"),
                            color: Colors.lightBlue,
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ];
        },
        body: ListView.builder(//列表區
          itemCount: 30,
          itemBuilder: (_, index) {
            return Container(
              height: 60,
              alignment: Alignment(0, 0),
              child: Text("數據$index"),
            );
          },
        ),
      ),
    );
  }
}

class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
  _SliverAppBarDelegate({
    @required this.minHeight,
    @required this.maxHeight,
    @required this.child,
  });

  final double minHeight;
  final double maxHeight;
  final Widget child;

  @override
  double get minExtent => minHeight;

  @override
  double get maxExtent => maxHeight;

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return SizedBox.expand(child: child);
  }

  @override
  bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
    return maxHeight != oldDelegate.maxHeight ||
        minHeight != oldDelegate.minHeight ||
        child != oldDelegate.child;
  }
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章