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

Flutter中GridView.builder动态更新容器颜色的GetX实现问题

问题:GetX状态管理下GridView容器颜色无法随audioPlayerCurrentIndex更新

通过点击“+”按钮使用GridView.builder创建3个容器,采用GetX框架管理状态,期望点击播放按钮调用playAudio()方法播放音频时,依据audioPlayerCurrentIndex的值动态切换对应容器的颜色。但实际audioPlayerCurrentIndex更新后,GridView的容器索引未同步更新,始终固定为2,无法实现预期的颜色变化效果。

核心代码

GridView.builder代码

Obx(
  () => GridView.builder(
    itemCount: c.gridItems.length,
    shrinkWrap: true,
    gridDelegate:
        SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 4,
            crossAxisSpacing: 20.dp,
            mainAxisSpacing: 10.dp,
            mainAxisExtent: 60.dp),
    itemBuilder: (BuildContext context, int index) {
      final isCurrentContainer =
          (index == c.audioPlayerCurrentIndex % 3);
      Color containerColor = isCurrentContainer
          ? Colors.blue
          : Colors.grey;

      return GestureDetector(
        onTap: () { 

          showDialog(
            context: context,
            builder: (BuildContext context) =>
                StatefulBuilder(
              builder: (context, state) => KeysDialog(),
            ),
          );
        },
        child: Obx(
          () => Container(
            width: 60.dp,
            height: 60.dp,
            color: containerColor,
            child: Center(
              child: Text(
                c.gridItems[index],
                style: white22TextStyle,
              ),
            ),
          ),
        ),
      );
    },
  ),
)

GetX控制器代码

class Controller extends GetxController {
  var gridItems = [].obs;

  var isMetronomeSelected = false.obs;
  var isBassSelected = false.obs;
  var isDrumsSelected = false.obs;

  var tonalitySelected = 'Major'.obs;
  var keySelected = 'A'.obs;
  var rhythmsFolderSelected = 'Slow Dancing'.obs;
  var bpmSliderValue = 95.0.obs;

  var assetSources = [].obs;
  var audioPlayerCurrentIndex = 0;
  var audioPlayerLoopCount = 0.obs;
}

playAudio()方法代码

Future<void> playAudio() async {
    await audioPlayer
        .play(AssetSource(c.assetSources[c.audioPlayerCurrentIndex]));
    print(c.assetSources.length);
    print(c.assetSources);

    await audioPlayer.onPlayerComplete.first;

    c.audioPlayerLoopCount.value++;

    // Check if all audios have played the same number of times
    if (c.audioPlayerLoopCount.value == c.assetSources.length) {
      c.audioPlayerLoopCount.value = 0;

      c.audioPlayerCurrentIndex = 0;
      playAudio();
    } else {
      // Play the next audio
      c.audioPlayerCurrentIndex =
          (c.audioPlayerCurrentIndex + 1) % c.assetSources.length;
      playAudio();
    }
  }

解决方案

问题出在**audioPlayerCurrentIndex没有被声明为GetX的可观察变量**,GetX只能监听.obs标记的变量变化,普通int变量的更新不会触发UI重建。

修改步骤:

  1. 将Controller中的audioPlayerCurrentIndex改为可观察变量:
// 替换原有的普通int声明
var audioPlayerCurrentIndex = 0.obs;
  1. 在UI中访问时添加.value:
// 原代码
// final isCurrentContainer = (index == c.audioPlayerCurrentIndex % 3);
// 修改为
final isCurrentContainer = (index == c.audioPlayerCurrentIndex.value % 3);
  1. 移除多余的内层Obx:
    内层Obx包裹Container是不必要的,因为containerColor的判断依赖外层Obx监听的变量,移除后可以避免不必要的UI重建:
// 原代码的child部分
// child: Obx(
//   () => Container(...),
// ),
// 修改为
child: Container(
  width: 60.dp,
  height: 60.dp,
  color: containerColor,
  child: Center(
    child: Text(
      c.gridItems[index],
      style: white22TextStyle,
    ),
  ),
),
  1. 更新playAudio()中对变量的赋值:
    因为现在audioPlayerCurrentIndex是RxInt,赋值时需要用.value:
// 原代码
// c.audioPlayerCurrentIndex = 0;
// 修改为
c.audioPlayerCurrentIndex.value = 0;

// 原代码
// c.audioPlayerCurrentIndex = (c.audioPlayerCurrentIndex + 1) % c.assetSources.length;
// 修改为
c.audioPlayerCurrentIndex.value = (c.audioPlayerCurrentIndex.value + 1) % c.assetSources.length;

原理说明

GetX的响应式依赖于可观察变量(Rx类型),当变量被标记为.obs后,每次修改.value时都会通知所有依赖它的Obx组件重建UI。之前的普通int变量更新时,GetX无法感知变化,所以GridView不会重新计算isCurrentContainer的值,导致颜色始终不变。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 01:53:19