flutter实现底部Tab和顶部导航条切换

815 阅读2分钟
原文链接: blog.csdn.net

底部Tab:使用BottomNavigationBar来实现,很简单。不过多解释,都有注释。

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

class _IndexPageState extends State<IndexPage> {
  List<BottomNavigationBarItem> tabs = [
    BottomNavigationBarItem(
      icon: Icon(CupertinoIcons.home),
      title: Text("首页"),
    ),
    BottomNavigationBarItem(
      icon: Icon(CupertinoIcons.search),
      title: Text("分类"),
    ),
    BottomNavigationBarItem(
      icon: Icon(CupertinoIcons.shopping_cart),
      title: Text("购物车"),
    ),
    BottomNavigationBarItem(
      icon: Icon(CupertinoIcons.profile_circled),
      title: Text("我的"),
    ),
  ];

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

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

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Scaffold(
        body: PageView(
          controller: _controller,
          children: pages,
          physics: NeverScrollableScrollPhysics(),//禁止页面滚动
        ),
        bottomNavigationBar: BottomNavigationBar(
          currentIndex: currentIndex,
          items: tabs,
          type: BottomNavigationBarType.fixed,
          onTap: (index) {
            _controller.jumpToPage(index);
            setState(() {
              currentIndex = index;
            });
          },
        ),
      ),
    );
  }
}

顶部Tab:

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(),
                  ],
                ),
              )
            ],
          ),
        ),

——————————————————————————————————————————————————————

有些需求会要求实现某部分布局滑到顶部后吸顶悬浮,可以是一个tabbar,也可以是一个别的组件,但是目的都是让其吸顶悬浮在那,示例代码如下:

class MyScoreFragment extends StatefulWidget {
  @override
  _MyScoreFragmentState createState() => _MyScoreFragmentState();
}

class _MyScoreFragmentState extends State<MyScoreFragment>
    with AutomaticKeepAliveClientMixin {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ScrollConfiguration(
        behavior: MyBehavior(),
        child: NestedScrollView(
          headerSliverBuilder: (context, innerBoxIsScrolled) {
            return [
              _header(),
              _stickyHeader(),
            ];
          },
          body: _listData(),
        ),
      ),
    );
  }

  @override
  void initState() {
    super.initState();
  }

  @override
  bool get wantKeepAlive => true;
}

//可折叠头
Widget _header() {
  return SliverAppBar(
      backgroundColor: Colors.white,
      automaticallyImplyLeading: false,
      expandedHeight: 120,
      flexibleSpace: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Image.asset("images/center_11.png", width: 40, height: 40),
          Container(
            margin: EdgeInsets.only(top: 10),
            child: RichText(
              text: TextSpan(
                children: [
                  TextSpan(
                    text: "总积分:",
                    style: TextStyle(
                      color: Color.fromRGBO(135, 135, 135, 1),
                      fontSize: 14,
                    ),
                  ),
                  TextSpan(
                    text: totalScore,
                    style: TextStyle(
                      color: Color.fromRGBO(255, 153, 0, 1),
                      fontSize: 14,
                    ),
                  ),
                ],
              ),
            ),
          ),
          Container(
            margin: EdgeInsets.only(top: 10),
            child: RichText(
              text: TextSpan(
                children: [
                  TextSpan(
                    text: "可兑换积分:",
                    style: TextStyle(
                      color: Color.fromRGBO(135, 135, 135, 1),
                      fontSize: 14,
                    ),
                  ),
                  TextSpan(
                    text: canExchangeScore,
                    style: TextStyle(
                      color: Color.fromRGBO(135, 135, 135, 1),
                      fontSize: 14,
                    ),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
}

//粘性头
Widget _stickyHeader() {
  return SliverPersistentHeader(
    pinned: true,
    delegate: _SliverAppBarDelegate(
      Container(
        height: 40,
        color: Colors.lightBlue,
        child: Row(
          children: <Widget>[
            Expanded(
              child: Container(
                alignment: Alignment(0, 0),
                child: Text(
                  "标题",
                  style: TextStyle(color: Colors.white),
                ),
              ),
            ),
            Expanded(
              child: Container(
                alignment: Alignment(0, 0),
                child: Text(
                  "观看形式",
                  style: TextStyle(color: Colors.white),
                ),
              ),
            ),
          ],
        ),
      ),
    ),
  );
}

//列表布局
  Widget _listData() {
    return Container(
      child: ListView.builder(
        itemCount: _list.length,
        itemBuilder: (context, index) {
          return _item(_list[index]);
        },
      ),
    );
  }

class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
  _SliverAppBarDelegate(this._container);

  final Container _container;

  @override
  double get minExtent => 40;

  @override
  double get maxExtent => 40;

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return _container;
  }

  @override
  bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
    return false;
  }
}