Flutter:竖向步骤条,类似查看物流组件

工作中写到了一个类似步骤条的样式,记录一下, 抽空将其改成发货查看物流模板。
在这里插入图片描述

页面

import 'package:dogex/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 NewsListPage extends GetView<NewsListController> {
    
    
  const NewsListPage({
    
    super.key});

  // 时间
  Widget _buildTime() {
    
    
    return <Widget>[
      TDImage(assetUrl: 'assets/img/home4.png',width: 48.w,height: 48.w,),
      SizedBox(width: 10.w,),
      TextWidget.body('2/06',size: 40.sp,color: AppTheme.colorfff,weight: FontWeight.w600),
      SizedBox(width: 15.w,),
      TextWidget.body('星期四',size: 24.sp,color: AppTheme.color6C7481,weight: FontWeight.w600),
    ].toRow();
  }

  // 列表
  Widget _buildList() {
    
    
    return SliverList(
      delegate: SliverChildBuilderDelegate(
        (context, index) {
    
    
          return IntrinsicHeight(
            child: <Widget>[
              // 左边圆圈
              <Widget>[
                <Widget>[].toRow().tight(width: 14.w,height: 14.w)
                .border(all: 2,color: AppTheme.colorfff)
                .backgroundColor(AppTheme.blockBgColor)
                .clipRRect(all: 7.w),
                Expanded(
                  child: TDDivider(width: 1,color: AppTheme.colorfff,),
                )
              ].toColumn(),
              // 右边文章内容
              <Widget>[
                // 时间
                TextWidget.body('11:21',size: 24.sp,color: AppTheme.color666,),
                SizedBox(height: 20.w),
                // 标题
                TextWidget.body('美国两家律师事务所起诉Pump.fun',size: 26.sp,color: AppTheme.colorfff,),
                SizedBox(height: 30.w),
                // 内容
                TextWidget.body(
                  index == 0 ?
                  '金色财经报道,据 Cointelegraph 报道,Pump.fun 因涉嫌使用两家律师事务所的标志和名称而收到一封停止令,这两家律师事务所目前正在起诉该平台。美国律师事务所 Bunwick Law 在 X平台的声明中表示,该公司和 WolfPopper 已向 Pump.fun 发出了一封停止令,要求"立即删除"Dog Shit Going NoWhere(DOGSHIT2)和其他代币这些代币通过未经许可使用知识产权(包括其徽标和名称)"冒充了我们的公司"。据 Pump.fun称,多名用户以各种配置使用Burwick Law和Wolf Popper的名称和微标创建了代币。还有一些代币使用了Burwick Law员工和其在针对Pump.fun的诉讼中的一名客户的姓名和肖像。'
                  : '其他内容',
                  size: 24.sp,color: AppTheme.color999,
                ),
                SizedBox(height: 30.w),
                // 查看原文
                TextWidget.body('查看原文',size: 24.sp,color: AppTheme.primaryBlue,textAlign: TextAlign.end,).width(650.w),
                SizedBox(height: 60.w),
              ].toColumn(crossAxisAlignment: CrossAxisAlignment.start).width(650.w),
            ].toRow(mainAxisAlignment: MainAxisAlignment.spaceBetween,crossAxisAlignment: CrossAxisAlignment.start),
          );
        },
        childCount: 10,
      ),
    );
  }

  // 主视图
  Widget _buildView() {
    
    
    return CustomScrollView(
      slivers: [
        SizedBox(height: 30.w).sliverToBoxAdapter(),
        _buildTime().sliverToBoxAdapter().sliverPaddingHorizontal(30.w),
        SizedBox(height: 30.w).sliverToBoxAdapter(),
        _buildList().sliverPaddingHorizontal(30.w),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    
    
    return GetBuilder<NewsListController>(
      init: NewsListController(),
      id: "news_list",
      builder: (_) {
    
    
        return Scaffold(
          backgroundColor: AppTheme.pageBgColor, // 自定义颜色
          appBar: TDNavBar(
            height: 44,
            title: '资讯',
            titleColor: AppTheme.colorfff,
            titleFontWeight: FontWeight.w600,
            backgroundColor: AppTheme.navBgColor,
            screenAdaptation: true,
            useDefaultBack: false,
            leftBarItems: [
              TDNavBarItem(icon: TDIcons.chevron_left, iconSize: 24, iconColor: AppTheme.colorfff,action: (){
    
    
                Get.back();
              }),
            ],
          ),
          body: SmartRefresher(
            controller: controller.refreshController,
            enablePullUp: true, // 启用上拉加载
            onRefresh: controller.onRefresh, // 下拉刷新回调
            onLoading: controller.onLoading, // 上拉加载回调
            footer: SmartRefresherFooterWidget(textColor: AppTheme.colorfff,), // 底部加载更多组件
            header: SmartRefresherHeaderWidget(textColor: AppTheme.colorfff,), // 头部刷新组件
            child: _buildView()
          )
        );
      },
    );
  }
}

控制器

import 'package:get/get.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
// import 'package:dogex/common/index.dart';

class NewsListController extends GetxController {
    
    
  NewsListController();

  // 查看详情
  void goNewsDetail(String id) {
    
    
    Get.toNamed('/newsDetail',arguments: {
    
    'id': id});
  }

  List items = [];

  /*
  * 分页
  * */
  final RefreshController refreshController = RefreshController(
    initialRefresh: true,
  );
  // int _page = 1;
  Future<bool> _loadNewsSell(bool isRefresh) async {
    
    
    return false;
    // var result = await HomeApi.noticesList(PageListReq(
    //   pageNo:isRefresh ? 1:_page,
    //   pageSize:20
    // ));
    // 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(["news_list"]);
  }

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



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


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

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