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;
  }
}

 

 

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