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

Flutter同页面动态切换Widget:菜单与右侧面板通信方案咨询

Flutter 同页面Stateful Widget通信(菜单切换右侧面板)

方法一:父组件统一管理状态 + 回调

这是适合新手的基础方案,逻辑清晰直接:

  • 在Dashboard的State里维护一个_selectedOptionIndex变量,初始值设为0(对应默认显示的Option1)
  • 给Menu组件传递一个回调函数,菜单选项被点击时,把选中的索引传给Dashboard
  • Dashboard根据当前选中的索引,渲染对应的右侧面板

代码示例:

// Dashboard 父组件
class Dashboard extends StatefulWidget {
  @override
  _DashboardState createState() => _DashboardState();
}

class _DashboardState extends State<Dashboard> {
  int _selectedOptionIndex = 0;

  // 菜单点击后的回调,更新选中状态
  void _onMenuTap(int index) {
    setState(() {
      _selectedOptionIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        // 把回调和选中状态传给Menu
        Menu(onOptionTap: _onMenuTap, selectedIndex: _selectedOptionIndex),
        // 根据选中索引渲染对应面板
        Expanded(child: _getCurrentPanel()),
      ],
    );
  }

  Widget _getCurrentPanel() {
    switch (_selectedOptionIndex) {
      case 0:
        return Option1Panel();
      case 1:
        return Option2Panel();
      case 2:
        return Option3Panel();
      default:
        return Option1Panel();
    }
  }
}

// Menu子组件
class Menu extends StatelessWidget {
  final Function(int) onOptionTap;
  final int selectedIndex;

  const Menu({required this.onOptionTap, required this.selectedIndex});

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: 200,
      child: Column(
        children: [
          GestureDetector(
            onTap: () => onOptionTap(0),
            child: Container(
              color: selectedIndex == 0 ? Colors.blue[100] : Colors.transparent,
              padding: const EdgeInsets.all(16),
              child: const Text("Option 1"),
            ),
          ),
          GestureDetector(
            onTap: () => onOptionTap(1),
            child: Container(
              color: selectedIndex == 1 ? Colors.blue[100] : Colors.transparent,
              padding: const EdgeInsets.all(16),
              child: const Text("Option 2"),
            ),
          ),
          // 更多菜单选项依此类推
        ],
      ),
    );
  }
}

// 示例面板组件
class Option1Panel extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return const Center(child: Text("Option 1的专属内容"));
  }
}

class Option2Panel extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return const Center(child: Text("Option 2的专属内容"));
  }
}

方法二:用Riverpod实现状态共享(修正你之前的尝试)

如果页面组件较多,用状态管理更省心,你之前没生效大概率是缺少关键配置:

  1. 先定义一个状态Provider:
final selectedOptionProvider = StateProvider<int>((ref) => 0);
  1. Menu组件里通过ref.read更新状态:
class Menu extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final selectedIndex = ref.watch(selectedOptionProvider);
    return SizedBox(
      width: 200,
      child: Column(
        children: [
          GestureDetector(
            onTap: () => ref.read(selectedOptionProvider.notifier).state = 0,
            child: Container(
              color: selectedIndex == 0 ? Colors.blue[100] : Colors.transparent,
              padding: const EdgeInsets.all(16),
              child: const Text("Option 1"),
            ),
          ),
          GestureDetector(
            onTap: () => ref.read(selectedOptionProvider.notifier).state = 1,
            child: Container(
              color: selectedIndex == 1 ? Colors.blue[100] : Colors.transparent,
              padding: const EdgeInsets.all(16),
              child: const Text("Option 2"),
            ),
          ),
        ],
      ),
    );
  }
}
  1. Dashboard里监听状态变化,渲染对应面板:
class Dashboard extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final selectedIndex = ref.watch(selectedOptionProvider);
    return Row(
      children: [
        const Menu(),
        Expanded(child: _getCurrentPanel(selectedIndex)),
      ],
    );
  }

  Widget _getCurrentPanel(int index) {
    switch (index) {
      case 0:
        return const Option1Panel();
      case 1:
        return const Option2Panel();
      default:
        return const Option1Panel();
    }
  }
}

关键检查点(Riverpod生效必备)

必须在main.dart里用ProviderScope包裹整个App:

void main() {
  runApp(const ProviderScope(child: MyApp()));
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 14:07:39