Flutter顶部TabBar和表格TableRow

需求:

显示样式为这样

flutter 数据库 hive 分页 flutter tablerow_flutter 数据库 hive 分页

1、可左右滑动切换表格

2、网络请求:一、切换才请求页面,二、表格有页码,支持上下拉刷新加载更多

3、表格做缓存处理(用户滑到哪里,切换表格再切回来还是那个位置)

4、点击行触发事件跳转

5、跳转后下一个页面影响到该页面的数据(重新更新数据)

UI代码分析

TabBar

如果单独写TabBar的话,会直接占满整个屏幕的宽度,所以外面需要套一层Container控制它的宽高。

TabBar的controller为

_tabController = TabController(length: titleModel.length, vsync: this);

// 标题
  void setTitleModel() {
    titleModel = [];
    titleModel.add('第一个表格名称');
    titleModel.add('第二个表格名称');
  }

如果有需要监听滑动切换的需求,我也用不着,所以这个可以删掉

_tabController.addListener(() {
      print(_tabController.index);
    });

整体结构为 行(TabBar + TabBarView),未选中样式和选中样式都可以更改

Widget _successWidget() {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Padding(padding: const EdgeInsets.fromLTRB(15, 10, 0, 0),child: Container(
          width: 192,
          height: 30,
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.circular(4),
            border: Border.all(width: 1, color: AppColor.themeBlue),
          ),
          child: TabBar(
              controller: _tabController,

              //未选中样式
              unselectedLabelColor: AppColor.themeBlue,
              unselectedLabelStyle: const TextStyle(
                  fontWeight: FontWeight.normal,
                  fontSize: 15,
                  color: Colors.white),
              indicator: const BoxDecoration(
                color: AppColor.themeBlue,
              ),
              //选中样式
              labelColor: AppColor.white,
              labelStyle: const TextStyle(
                fontWeight: FontWeight.normal,
                fontSize: 15,),

              tabs: titleModel.map((item) => Tab(text: item)).toList()),),),
        const Padding(padding: EdgeInsets.fromLTRB(15, 10, 0, 20),child:
        Text('点击列表可查看明细内容',style: TextStyle(
          fontSize: 12,
          fontWeight: FontWeight.normal,
          color: AppColor.grey99
        ),),),
        Expanded(child: TabBarView(
          controller: _tabController,
          children: [
            // 第一个表格
            ....(),
            // 第二个表格
            ....(),
          ],),
        )
      ],
    );
  }

整体的框架做好后,开始着手做表格内容,我把网络请求放在了表格的显示上,这样就可以实现切换才请求页面

用到大概的库

import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:provider/provider.dart';
import 'package:event_bus/event_bus.dart';

整体的框架为 EasyRefresh上下拉刷新,包裹着SingleChildScrollview 包含的Table表格

Table的cell为TableRow

第一行为标题

Widget _tablePayWidget(BuildContext context) {
    final List<TableRow> list = [];
    list.add(const TableRow(
        decoration:  BoxDecoration(
          color: AppColor.greyF4,
        ),
        children: [
          Padding(padding: EdgeInsets.fromLTRB(0, 12, 0, 12),
            child: Text('第一个',style:
            TextStyle(
              fontSize: 14,
                fontWeight: FontWeight.bold,
                color: Color(0xff333333)),
              textAlign: TextAlign.center,),),
          Padding(
            padding: EdgeInsets.fromLTRB(0, 12, 0, 12),
            child: Text('第二个', style: TextStyle(
                fontSize: 14,
                fontWeight: FontWeight.bold,
                color: Color(0xff333333)),
              textAlign: TextAlign.center,),),

          Padding(
            padding:  EdgeInsets.fromLTRB(0, 12, 0, 12),
            child: Text('第三个', style: TextStyle(
                fontSize: 14,
                fontWeight: FontWeight.bold,
                color: Color(0xff333333)),
              textAlign: TextAlign.center,),),

          Padding(
            padding: EdgeInsets.fromLTRB(0, 12, 0, 12),
            child: Text('第四个', style: TextStyle(
                fontSize: 14,
                fontWeight: FontWeight.bold,
                color: Color(0xff333333)),
              textAlign: TextAlign.center,),
          ),
        ]
    ));
    if(_provider.applyModel.list != null) {
        _provider.applyModel.list!.forEach((item) {
          list.add(_containTableRow(item));
        });

    }
    // 滑动加载
    return EasyRefresh(
      controller: _refreshController,
      header: TGHeader(),
      footer: TGFooter(),
      onRefresh: () async {
        _refreshController.resetLoadState();
        await _provider.getApplyModel();
      },
      onLoad: () async {
        await _provider.onLoadTabModel();
      },

      child: SingleChildScrollView(child: Padding(
        padding: const EdgeInsets.fromLTRB(15, 0, 15, 0),
        child: Table(
          // 表格比例
          columnWidths: <int,TableColumnWidth>{
            0: FixedColumnWidth((MediaQuery.of(context).size.width - 30)*0.216),
            1: FixedColumnWidth((MediaQuery.of(context).size.width - 30)*0.352),
            2: FixedColumnWidth((MediaQuery.of(context).size.width - 30)*0.216),
            3: FixedColumnWidth((MediaQuery.of(context).size.width - 30)*0.216),
          },

          border: TableBorder.all(color: AppColor.greyDD,width: 0.5,style: BorderStyle.solid),
          defaultVerticalAlignment: TableCellVerticalAlignment.middle,
          children: list,
        ),
      ),),
    );
  }

Tablechildern:必须是TableRow,但TableRow却不继承Widget,不能在外面套一层GestureDetector的点击事件,所以只能在TableRow里的每个item外面套一层GestureDetector,实属麻烦。 TableRow的写法与第一行的写法差不多,只是把请求回来的数据放上去,再把TableRow通过List.add所以我就不展示代码了

if(_provider.applyModel.list != null) {
        _provider.applyModel.list!.forEach((item) {
          list.add(_containTableRow(item));
        });

    }
表格做缓存处理(用户滑到哪里,切换表格再切回来还是那个位置)

列表需要保存

继承AutomaticKeepAliveClientMixin

class .....Widget extends State<.....> with AutomaticKeepAliveClientMixin{
  @override
  bool get wantKeepAlive => true;
跳转后下一个页面影响到该页面的数据(重新更新数据)

用到的是通知

我的通知是封装过的,所以看看就完事了,真写的话参考

import 'package:event_bus/event_bus.dart';

代码部分

接收通知刷新页面

//刷新页面
  void _eventRefreshData(){
    EventBusUtils.on<PaymentRecordTableApplyNotification>(
          (...Notification event){
        ///如果页面存在
        if(mounted){
          _provider.getData();
        }
      },
    );
  }
class ...Notification {

}

有需要刷新的操作

EventBusUtils.fire(...Notification());