Flutter跨平台移动端开发丨顶部导航栏 TabBar Widget

支持左右滑动切换、不限 item 数量的 tabbar 是分类信息列表展示必不可少的组件,在 flutter 中可通过 AppBar + TabBar + PageView + ListView 完成这个需求


TabBar 部件

支持修改 tab 背景颜色、底部横线颜色,tab 上的按钮样式以及对应切换的页面,可通过 List 传入,这样可以支持更多拓展需求

import 'package:delongzhixuan/main/tab/MainTab.dart';
import 'package:flutter/material.dart';

/**
 * @des 顶部 tab 部件
 * @author liyongli 20190704
 * */
class TabWidget extends StatefulWidget{

  // item 组件
  List<Widget> tabItems;

  // item 组件对应的 widget
  List<Widget> tabItemWidgets;

  // tab 的背景颜色
  Color backgroundColor;

  // item 底部横线颜色
  Color indicatorColor;

  // item 对应的 widget 控制器
  PageController pageController;

  TabWidget({
    @required this.tabItems,
    @required this.tabItemWidgets,
    this.backgroundColor,
    this.indicatorColor,
    this.pageController
  }):super();

  @override
  State<StatefulWidget> createState() => _TabWidgetState();

}

/**
 * @des 顶部 tab 部件 State
 * @author liyongli 20190704
 * */
class _TabWidgetState extends State<TabWidget> with SingleTickerProviderStateMixin{

  TabController tabController;

  @override
  void initState() {
    super.initState();
    tabController = new TabController(length: widget.tabItems.length, vsync: this);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(

        // 顶部 TabBar
        title: Text(MainTabState.pageNameList[1], style: MainTabState.appbarTestStyle),
        backgroundColor: MainTabState.appbarBackgroundColor,
        centerTitle: true,
        bottom: TabBar(
          isScrollable: true, // 设置是否支持左右滑动
          controller: tabController, // 控制器
          indicatorColor: widget.indicatorColor, // item 底部横线颜色
          tabs: widget.tabItems, // 设置列表内容
        ),
      ),

      // TabBar 对应的 widget
      body: new PageView(
        controller: widget.pageController,
        children: widget.tabItemWidgets,
        onPageChanged: (index){
          tabController.animateTo(index);
        },
      ),
    );
  }

  @override
  void dispose() {
    tabController.dispose();
    super.dispose();
  }
}

TabBar 部件 item 对应的页面

也就是 ListView 部分,修改 initPageWidget 返回的 widget 为你需要的样式即可

import 'package:flutter/material.dart';

/**
 * @des 顶部 tab 部件对应的 widget
 * @author liyongli 20190704
 * */
class TabItemWidget extends StatefulWidget {

  String itemIndex;

  TabItemWidget(this.itemIndex);

  @override
  State<StatefulWidget> createState() => _TabItemWidgetState();

}

/**
 * @des 顶部 tab 部件对应的 widget state
 * @author liyongli 20190704
 * */
class _TabItemWidgetState extends State<TabItemWidget> {

  @override
  Widget build(BuildContext context) {
    return initPageWidget();
  }

  /**
   * 初始化 page widget
   * */
  Widget initPageWidget(){
    return ListView.builder(itemBuilder: (context, i){
      return Container(
        alignment: Alignment.center,
        width: double.maxFinite,
        height: 100.0,
        decoration: BoxDecoration(
          border: Border(bottom: BorderSide(color: Color(0xff000000), width: 0.2))
        ),
        child: Text("${widget.itemIndex} - $i", style: TextStyle(color: Color(0xff000000), fontSize: 20.0),),
      );
    });
  }
}

TabBar 部件如何应用

import 'package:delongzhixuan/utils/tab/TabWidget.dart';
import 'package:delongzhixuan/utils/tab/TabItemWidget.dart';
import 'package:flutter/material.dart';

/**
 * @des 产品首页
 * @author liyongli 20190704
 * */
class MainProduct extends StatefulWidget {

  @override
  State<StatefulWidget> createState() => _MainProductState();

}

/**
 * @des 产品首页 State
 * @author liyongli 20190704
 * */
class _MainProductState extends State<MainProduct> {

  // 控制器
  PageController pageController;

  // 模拟数据
  List<String> items = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10",];

  // tabbar 按钮集合
  List<Widget> tabItems = new List<Widget>();

  // tabbar 按钮对应的页面集合
  List<Widget> tabItemWidgets = new List<Widget>();

  @override
  void initState() {
    super.initState();
    pageController = new PageController();
    tabItems = _initTabItems(items, tabItems, false);
    tabItemWidgets = _initTabItemWidgets(items, tabItemWidgets);
    setState(() { });
  }

  @override
  Widget build(BuildContext context) {
    return _initPageWidget(context);
  }

  /**
   * 初始化 page widget
   * */
  Widget _initPageWidget(BuildContext context){
    return new TabWidget(
      tabItems: tabItems,
      tabItemWidgets: tabItemWidgets,
      pageController: pageController,
      indicatorColor: Colors.yellow,
    );
  }

  /**
   * 初始化 tab item 部件
   *
   * @params itemNameList 存储 tab item 名字的集合
   * @params itemWidgetList 转化完成后返回的集合
   * @params clear 是否需要在转化开始前,先行清空返回数组内的数据,主要用于应对分页加载刷新时的场景
   *
   * @return 已完成转化的 widget 集合
   * */
  List<Widget> _initTabItems(List<String> itemNameList, List<Widget> itemWidgetList, bool clear){

    // 检查传入的名字集合是否有数据,若没有数据则 return null
    if(null == itemNameList || itemNameList.length < 1){
      return null;
    }

    // 检查目标集合是否为空,为空则创建
    if(null == itemWidgetList){
      itemWidgetList = new List<Widget>();
    }

    // 检查是否需要先行清空 widget 集合数据
    if(clear && itemWidgetList.length > 0){
      itemWidgetList.clear();
    }

    // 开始转化
    for(var i = 0 ; i < itemNameList.length ; i++){
      itemWidgetList.add(
          new FlatButton(
              onPressed: (){pageController.jumpTo(MediaQuery.of(context).size.width * i);},
              child: Text(itemNameList[i], style: TextStyle(color: Color(0xffffffff)),)
          )
      );
    }

    return itemWidgetList;
  }

  /**
   * 初始化 tab item 对应的 widget(ListView 列表)
   *
   * @params itemNameList 存储 tab item 名字的集合
   * @params itemWidgetList 转化完成后返回的集合
   *
   * @return 已完成初始化的 tab item 对应的 widget 的数据集合
   * */
  List<Widget> _initTabItemWidgets(List<String> itemNameList, List<Widget> itemWidgetList){

    // 检查传入的名字集合是否有数据,若没有数据则 return null
    if(null == itemNameList || itemNameList.length < 1){
      return null;
    }

    // 检查目标集合是否为空,为空则创建
    if(null == itemWidgetList){
      itemWidgetList = new List<Widget>();
    }

    // 开始创建
    for(var i = 0 ; i < itemNameList.length ; i++){
      itemWidgetList.add(new TabItemWidget(itemNameList[i]));
    }

    return itemWidgetList;
  }

}

运行结果

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券