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

Flutter菜单动画触发问题:点击单个按钮所有动画同时启动如何解决

问题原因

你目前所有按钮共用同一个全局selected布尔状态,只要这个状态更新,所有绑定了这个状态的AnimatedContainer都会同步响应,所以才会出现点一个所有按钮都同步动的情况。

解决方案

把单布尔状态替换为能区分每个按钮选中状态的存储结构,这里提供两种常用实现:

  • 单选模式:一次只能有一个按钮处于选中状态,用存储当前选中索引的变量实现
  • 多选模式:允许多个按钮同时选中,用布尔数组实现

这里以最常用的单选模式为例,修改后的代码如下:

修改后的main.dart

import 'package:flutter/material.dart';
import './button.dart';

void main() => runApp(const MyStatefulWidget());

class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({Key? key}) : super(key: key);
  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  // 替换原来的单布尔变量,存储当前选中的索引,null表示没有选中项
  int? selectedIndex;

  Container countryPageView() {
    final PageController controller =
        PageController(initialPage: 1, keepPage: true, viewportFraction: 0.35);
    return Container(
      height: 300,
      child: PageView.builder(
        scrollDirection: Axis.horizontal,
        controller: controller,
        itemCount: 5,
        physics: const BouncingScrollPhysics(),
        itemBuilder: (BuildContext context, int index) {
          return Container(
            child: gestureDetectorOntap(index),
          );
        },
      ),
    );
  }

  GestureDetector gestureDetectorOntap(int index) {
    return GestureDetector(
      onTap: () {
        setState(() {
          // 如果点击的是已选中的按钮就取消选中,否则选中当前点击的按钮
          selectedIndex = selectedIndex == index ? null : index;
        });
      },
      child: Column(
        children: [Text('menu $index'), button(selectedIndex == index)], // 只有当前索引匹配时才传选中状态true
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: countryPageView(),
      ),
    );
  }
}

可选优化(button.dart规范调整)

你现有button.dart可以直接复用无需修改,如果要符合Flutter官方开发规范,建议改成无状态Widget形式:

import 'package:flutter/material.dart';

class AnimatedMenuButton extends StatelessWidget {
  final bool selected;
  const AnimatedMenuButton({super.key, required this.selected});

  @override
  Widget build(BuildContext context) {
    return AnimatedContainer(
      width: selected ? 200.0 : 100.0,
      height: selected ? 100.0 : 200.0,
      color: selected ? Colors.red : Colors.blue,
      alignment: selected ? Alignment.center : AlignmentDirectional.topCenter,
      duration: const Duration(seconds: 2),
      curve: Curves.fastOutSlowIn,
      child: const FlutterLogo(size: 75),
    );
  }
}

如果需要实现多选效果,只需要把状态换成List<bool> selectedList = List.generate(5, (_) => false);,点击事件改成selectedList[index] = !selectedList[index];,传参时用button(selectedList[index])即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 09:09:03