You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用GetX解决Flutter底部标签切换时按钮状态重置问题

问题:底部标签切换时保存按钮状态重置,如何用GetX解决?

我尝试管理底部标签切换时按钮的状态,但每次切换标签后,按钮都会回到初始状态。以下是我的代码片段:

卡片列表函数

// 返回包含待管理状态按钮的卡片列表的函数
browseCard(List<AllJobsResult> itemList) {
    final jobOverviewController = Get.put(JobApplicationOverviewController());
    return ListView.builder(
      controller: jobPreferenceController.scrollController.value,
      shrinkWrap: true,
      itemCount: itemList.length,
      itemBuilder: (context, index) {
        var datas = itemList[index];
        var splitDate = datas.dateCreated.toString().split(".");
        var dateCreated = splitDate[0].split(" ");
        return itemList.length == 0
            ? CircularLoader()
            : GestureDetector(
                onTap: () async {
                  ...
                },
                child: Container(
                  child: Padding(
                    padding: const EdgeInsets.symmetric(
                      horizontal: 10.0,
                      vertical: 5.0,
                    ),
                    child:SaveJobBtn(
                                    isSaved: datas.isSaved,
                                    jobID: datas.id,
                                    showText: true,
                                  )
                            )
  }

自定义保存按钮组件

class SaveJobBtn extends StatefulWidget {
  bool isSaved;
  final int jobID;
  final bool showText;

  SaveJobBtn({Key key, this.isSaved, this.jobID, this.showText})
      : super(key: key);
  @override
  _SaveJobBtnState createState() => _SaveJobBtnState();
}

class _SaveJobBtnState extends State<SaveJobBtn> {
  bool isSavedJOb = false;

  @override
  void initState() {
    isSavedJOb = widget.isSaved;
    super.initState();
  }

  var ctr = Get.put(BrowseAllJobsController());

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        setState(() {
          ctr.saveJob(widget.jobID);
          isSavedJOb = !isSavedJOb; // 切换按钮状态
        });
      },
      child: Container(
        padding: EdgeInsets.all(6),
        decoration: BoxDecoration(
            color: isSavedJOb == false ? Colors.transparent : Color(0xffF6FCFF),
            borderRadius: BorderRadius.circular(4)),
        child: Row(children: [
          isSavedJOb == false
              ? SvgPicture.asset(
                  'assets/svgs/bookmark.svg',
                  color: isSavedJOb == false ? enumGrey3 : kPrimaryColor,
                  height: 20,
                )
              : Container(
                  height: 20,
                  padding: EdgeInsets.symmetric(horizontal: 4),
                  child: SvgPicture.asset(
                    'assets/svgs/bookmark_colored.svg',
                    height: 16,
                  ),
                ),
          widget.showText
              ? Text(
                  isSavedJOb == false ? ' Save' : ' Saved',
                  style: TextStyle(
                    fontFamily: 'GoogleFonts.dmSans',
                    fontWeight: FontWeight.w400,
                    color: isSavedJOb == false ? enumGrey3 : kPrimaryColor,
                    fontSize: 14,
                  ),
                )
              : SizedBox(),
        ]),
      ),
    );
  }
}
解决方案

核心问题是你将按钮状态存在了StatefulWidget的本地状态中,切换标签触发组件重建时,initState会重新从widget.isSaved赋值,而数据源itemList里的datas.isSaved并没有同步更新,导致状态重置。结合GetX的状态管理,需要把保存状态的逻辑移到GetX Controller中,而非组件本地。

步骤1:改造GetX Controller

将已保存职位的状态维护在Controller里,用Rx集合实现自动响应:

class BrowseAllJobsController extends GetxController {
  // 用RxSet存储已保存的jobID,状态变化自动通知UI更新
  final savedJobIds = <int>{}.obs;

  @override
  void onInit() {
    super.onInit();
    // 初始化时可从本地存储/接口加载已保存的职位ID
    // savedJobIds.addAll(loadSavedJobsFromLocal());
  }

  void saveJob(int jobId) {
    if (savedJobIds.contains(jobId)) {
      savedJobIds.remove(jobId);
      // 调用取消保存的接口逻辑
    } else {
      savedJobIds.add(jobId);
      // 调用保存职位的接口逻辑
    }
    // 可选:同步更新数据源中的isSaved状态,确保数据一致性
    // itemList.forEach((item) {
    //   if(item.id == jobId) item.isSaved = !item.isSaved;
    // });
  }

  // 判断指定职位是否已保存
  bool isJobSaved(int jobId) {
    return savedJobIds.contains(jobId);
  }
}

步骤2:重构SaveJobBtn为无状态组件

移除本地状态,直接依赖Controller的全局状态:

class SaveJobBtn extends StatelessWidget {
  final int jobID;
  final bool showText;

  const SaveJobBtn({Key? key, required this.jobID, required this.showText})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    final ctr = Get.find<BrowseAllJobsController>();
    return GestureDetector(
      onTap: () {
        ctr.saveJob(jobID);
      },
      child: Obx(() {
        bool isSavedJob = ctr.isJobSaved(jobID);
        return Container(
          padding: const EdgeInsets.all(6),
          decoration: BoxDecoration(
              color: isSavedJob ? const Color(0xffF6FCFF) : Colors.transparent,
              borderRadius: BorderRadius.circular(4)),
          child: Row(children: [
            isSavedJob
                ? Container(
                    height: 20,
                    padding: const EdgeInsets.symmetric(horizontal: 4),
                    child: SvgPicture.asset(
                      'assets/svgs/bookmark_colored.svg',
                      height: 16,
                    ),
                  )
                : SvgPicture.asset(
                    'assets/svgs/bookmark.svg',
                    color: enumGrey3,
                    height: 20,
                  ),
            if (showText)
              Text(
                isSavedJob ? ' Saved' : ' Save',
                style: TextStyle(
                  fontFamily: 'GoogleFonts.dmSans',
                  fontWeight: FontWeight.w400,
                  color: isSavedJob ? kPrimaryColor : enumGrey3,
                  fontSize: 14,
                ),
              )
            else
              const SizedBox(),
          ]),
        );
      }),
    );
  }
}

步骤3:更新卡片列表的按钮调用

不再传递isSaved参数,组件直接从Controller获取最新状态:

// 返回包含待管理状态按钮的卡片列表的函数
Widget browseCard(List<AllJobsResult> itemList) {
  final jobOverviewController = Get.put(JobApplicationOverviewController());
  return ListView.builder(
    controller: jobPreferenceController.scrollController.value,
    shrinkWrap: true,
    itemCount: itemList.length,
    itemBuilder: (context, index) {
      var datas = itemList[index];
      var splitDate = datas.dateCreated.toString().split(".");
      var dateCreated = splitDate[0].split(" ");
      return itemList.isEmpty
          ? const CircularLoader()
          : GestureDetector(
              onTap: () async {
                // ... 原逻辑保持不变
              },
              child: Container(
                child: Padding(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 10.0,
                    vertical: 5.0,
                  ),
                  child: SaveJobBtn(
                    jobID: datas.id,
                    showText: true,
                  ),
                ),
              ),
            );
    },
  );
}

关键说明

  • 把保存状态从组件本地迁移到GetX Controller的Rx集合,确保状态全局共享,组件重建时自动获取最新值
  • 用Obx包裹按钮UI,当savedJobIds变化时自动触发UI更新
  • 移除SaveJobBtn的isSaved参数,避免依赖数据源中的旧状态
  • 若需要保持数据源和状态一致,可在Controller的saveJob方法中同步更新itemList的isSaved字段

内容的提问来源于stack exchange,提问作者DOMINIC DANIEL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 10:25:21