Flutter:tab状态切换,订单列表页布局

发布于:2025-02-11 ⋅ 阅读:(40) ⋅ 点赞:(0)

在这里插入图片描述

view

import 'package:demo/common/index.dart';
import 'package:ducafe_ui_core/ducafe_ui_core.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';

import 'index.dart';

class OrderListPage extends GetView<OrderListController> {
  const OrderListPage({super.key});

  // tab切换
  Widget _buildTab() {
    return TDTabBar(
      controller: controller.tabController,
      tabs: controller.tabNames.map((e) => TDTab(text: e)).toList(),
      onTap: (index) {
        controller.onTapOrderStatus(index);
      },
      backgroundColor: Colors.white,
      showIndicator: true,
      indicatorColor: const Color(0xffe01e1e),
      labelColor: const Color(0xffe01e1e),
    );
  }

  // list 列表
  Widget _buildList() {
    return SmartRefresher(
      controller: controller.refreshController,
      enablePullUp: true, // 启用上拉加载
      onRefresh: controller.onRefresh, // 下拉刷新回调
      onLoading: controller.onLoading, // 上拉加载回调
      footer: const SmartRefresherFooterWidget(), // 底部加载更多组件
      header: const SmartRefresherHeaderWidget(), // 顶部下拉刷新组件
      child: ListView.builder(
        itemCount: 10,
        itemBuilder: (context, index) {
          return _buildItem();
        },
      ),
    );
  }

  // 商品item
  Widget _buildItem() {
    return <Widget>[
      // 状态
      <Widget>[
        TextWidget.body('订单编号:00556448656464156479',
            size: 20.sp, color: const Color(0xff999999)),
        TextWidget.body('待付款', size: 20.sp, color: const Color(0xff999999)),
      ].toRow(mainAxisAlignment: MainAxisAlignment.spaceBetween).height(61.w),
      const Divider(height: 1, color: Color(0xffE5E5E5)),
      // 商品列表
      <Widget>[
        <Widget>[
          TDImage(
            assetUrl: 'assets/img/user.png',
            width: 148.w,
            height: 148.w,
          ),
          SizedBox(width: 20.w),
          <Widget>[
            const TextWidget.body(
              '商品名称商品名称商品名称商品名称商品名称商品名称',
              maxLines: 1,
              overflow: TextOverflow.ellipsis,
            ),
            SizedBox(height: 10.w),
            TextWidget.body(
              '规格:白色,L',
              size: 24.sp,
              maxLines: 1,
              overflow: TextOverflow.ellipsis,
            ),
            SizedBox(height: 10.w),
            <Widget>[
              TextWidget.body(
                '¥588',
                size: 28.sp,
                color: const Color(0xffe01e1e),
                weight: FontWeight.w600,
              ),
              TextWidget.body(
                'x1',
                size: 20.sp,
              ),
            ].toRow(mainAxisAlignment: MainAxisAlignment.spaceBetween)
          ].toColumn(crossAxisAlignment: CrossAxisAlignment.start).expanded(),
        ].toRow().paddingOnly(top: 20.w, bottom: 20.w),
      ].toColumn(),
      const Divider(height: 1, color: Color(0xffE5E5E5)),
      // 底部状态按钮
      <Widget>[
        TextWidget.body('实付款:¥588', size: 26.sp),
        <Widget>[
          <Widget>[
            TextWidget.body(
              '取消订单',
              size: 26.sp,
              color: const Color(0xff999999),
            ),
          ]
              .toRow(mainAxisAlignment: MainAxisAlignment.center)
              .card(
                  color: const Color(0xfff6f6f6),
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(33.w)))
              .tight(width: 160.w, height: 66.w),
          SizedBox(width: 20.w),
          <Widget>[
            TextWidget.body(
              '立即付款',
              size: 26.sp,
              color: const Color(0xffffffff),
            ),
          ]
              .toRow(mainAxisAlignment: MainAxisAlignment.center)
              .card(
                  color: const Color(0xffe01e1e),
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(33.w)))
              .tight(width: 160.w, height: 66.w),
        ].toRow()
      ].toRow(mainAxisAlignment: MainAxisAlignment.spaceBetween).height(105.w)
    ]
        .toColumn(crossAxisAlignment: CrossAxisAlignment.start)
        .paddingHorizontal(30.w)
        .card()
        .paddingHorizontal(30.w)
        .tight(width: 690.w)
        .marginOnly(top: 20.w);
  }

  // 主视图
  Widget _buildView() {
    return <Widget>[
      _buildTab(),
      Expanded(child: _buildList()),
    ].toColumn();
  }

  @override
  Widget build(BuildContext context) {
    return GetBuilder<OrderListController>(
      init: OrderListController(),
      id: "order_list",
      builder: (_) {
        return Scaffold(
          backgroundColor: const Color(0xffF5F6FA),
          appBar: const TDNavBar(
            height: 45,
            title: '我的订单',
            titleFontWeight: FontWeight.w600,
            backgroundColor: Colors.white,
            screenAdaptation: true,
            useDefaultBack: true,
          ),
          body: SafeArea(
            child: _buildView(),
          ),
        );
      },
    );
  }
}

controller

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';

class OrderListController extends GetxController with GetTickerProviderStateMixin{
  OrderListController();
  // tab 控制器
  late TabController tabController;
  // tab 索引
  int tabIndex = 0;
  // tab 名称
  List<String> tabNames = ['全部', '待付款', '待发货', '待收货', '已完成'];
  // 订单状态改变
  onTapOrderStatus(int index){
    tabIndex = index;
    // 刷新订单列表
    refreshController.requestRefresh();
    update(["order_list"]);
  }


  // 订单列表
  List items = [];

  /*
  * 分页
  * refreshController:分页控制器
  * _page:分页
  * _limit:每页条数
  * _loadNewsSell:拉取数据(是否刷新)
  * onLoading:上拉加载新商品
  * onRefresh:下拉刷新
  * */
  final RefreshController refreshController = RefreshController(
    initialRefresh: true,
  );
  // int _page = 1;
  // int _limit = 20;
  Future<bool> _loadNewsSell(bool isRefresh) async {
    return false;
    // var result = await ProductApi.products(ProductsReq(
    //   page:isRefresh ? 1:_page,
    //     prePage:_limit
    // ));
    // if(isRefresh){
    //   _page = 1;
    //   items.clear();
    // }
    // if(result.isNotEmpty){
    //   _page++;
    //   items.addAll(result);
    // }
    // // 是否是空
    // return result.isEmpty;
  }

  // 上拉载入新商品
  void onLoading() async {
    if (items.isNotEmpty) {
      try {
        // 拉取数据是否为空 ? 设置暂无数据 : 加载完成
        var isEmpty = await _loadNewsSell(false);
        isEmpty
            ? refreshController.loadNoData()
            : refreshController.loadComplete();
      } catch (e) {
        refreshController.loadFailed(); // 加载失败
      }
    } else {
      refreshController.loadNoData(); // 设置无数据
    }
    update(["goods_list"]);
  }

  // 下拉刷新
  void onRefresh() async {
    try {
      await _loadNewsSell(true);
      refreshController.refreshCompleted();
    } catch (e) {
      refreshController.refreshFailed();
    }
    update(["goods_list"]);
  }

  _initData() {
    update(["order_list"]);
  }

  void onTap() {}

  @override
  void onInit() {
    super.onInit();
    tabController = TabController(length: tabNames.length, vsync: this);
  }

  @override
  void onReady() {
    super.onReady();
    _initData();
  }

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

点击tab切换时,如果不希望出现下拉刷新这个动作,可直接设置needMove: false属性

refreshController.requestRefresh(needMove: false);

进阶内容:从上个页面传tabIndex,指定当前索引位置

class OrderListController extends GetxController with GetSingleTickerProviderStateMixin {
  OrderListController();
  
  // tab 控制器
  late TabController tabController;
  // tab 索引
  int tabIndex = Get.arguments["tabIndex"] ?? 0;
  
  // 订单状态改变
  onTapOrderStatus(int index) {
    tabIndex = index;
    // 手动更新 TabController 的索引
    tabController.animateTo(index);
    // 刷新订单列表
    refreshController.requestRefresh();
    update(["order_list"]);
  }
  
  @override
  void onInit() {
    super.onInit();
    // 初始化时设置当前索引
    tabController = TabController(
      length: tabNames.length,
      vsync: this,
      initialIndex: tabIndex, // 设置初始索引
    );
    
    // 监听 tab 切换
    tabController.addListener(() {
      if (tabController.indexIsChanging) {
        tabIndex = tabController.index;
        update(["order_list"]);
      }
    });
  }
  
  @override
  void onClose() {
    super.onClose();
    tabController.dispose(); // 记得释放控制器
    refreshController.dispose();
  }
  
}