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

Flutter:如何通过接口数据动态生成Drawer中的ListTile?

问题描述

我通过fetchMenus()方法从接口获取菜单名称列表,希望将这些名称显示在Drawer的ListTile的Text组件中,请问该如何实现?

以下是我的相关代码:

模型类

class Menu {
  const Menu({
    required this.name,
    required this.folder,
  });

  final String name;
  final String folder;

  factory Menu.fromJson(Map<String, dynamic> json) => Menu(
    name: json["name"],
    folder: json["folder"],
  );

  Map<String, dynamic> toJson() => {
    "name": name,
    "folder": folder,
  };
}

接口请求代码

Future<List<Menu>> fetchMenus() async {
    final response =
        await http.get(Uri.parse('http://myUrl:3355/'));
    if (response.statusCode == 200) {
      var getMenusData = json.decode(response.body) as List;
      var listMenus = getMenusData.map((i) => Menu.fromJson(i)).toList();
      return listMenus;
    } else {
      throw Exception('Failed to load Menus');
    }
}

待修改的Drawer代码

Drawer(
  child: ListView(
    padding: EdgeInsets.zero,
    children: [
      const DrawerHeader(
        decoration: BoxDecoration(
          color: Colors.blue,
        ),
        child: Text('Drawer Header'),
      ),
      ListTile(
        title: const Text('Item 1'),
        onTap: () {
        },
      ),
      ListTile(
        title: const Text('Item 2'),
        onTap: () {
        },
      ),
    ],
  ),
);

解决方案

方法一:使用FutureBuilder(推荐)

直接用FutureBuilder包裹Drawer内的ListView,处理异步数据的加载、成功、失败状态:

Drawer(
  child: FutureBuilder<List<Menu>>(
    future: fetchMenus(),
    builder: (context, snapshot) {
      // 加载中显示加载指示器
      if (snapshot.connectionState == ConnectionState.waiting) {
        return const Center(child: CircularProgressIndicator());
      }
      // 加载失败显示错误信息
      if (snapshot.hasError) {
        return Center(child: Text('加载失败: ${snapshot.error}'));
      }
      // 加载成功,遍历菜单生成ListTile
      final menus = snapshot.data ?? [];
      return ListView(
        padding: EdgeInsets.zero,
        children: [
          const DrawerHeader(
            decoration: BoxDecoration(
              color: Colors.blue,
            ),
            child: Text('Drawer Header'),
          ),
          ...menus.map((menu) => ListTile(
                title: Text(menu.name),
                onTap: () {
                  // 可在此添加点击逻辑,比如根据menu.folder执行对应操作
                  Navigator.pop(context);
                },
              )),
        ],
      );
    },
  ),
);

方法二:在StatefulWidget中手动管理状态

如果需要更灵活的状态控制(比如支持重新加载、下拉刷新),可以将数据托管在State类中:

class YourPage extends StatefulWidget {
  const YourPage({super.key});

  @override
  State<YourPage> createState() => _YourPageState();
}

class _YourPageState extends State<YourPage> {
  late Future<List<Menu>> _menusFuture;

  @override
  void initState() {
    super.initState();
    // 页面初始化时加载菜单数据
    _menusFuture = fetchMenus();
  }

  // 重新加载菜单的方法
  void _reloadMenus() {
    setState(() {
      _menusFuture = fetchMenus();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('页面标题')),
      drawer: Drawer(
        child: FutureBuilder<List<Menu>>(
          future: _menusFuture,
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return const Center(child: CircularProgressIndicator());
            }
            if (snapshot.hasError) {
              return Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text('加载失败: ${snapshot.error}'),
                  const SizedBox(height: 16),
                  TextButton(
                    onPressed: _reloadMenus,
                    child: const Text('重新加载'),
                  ),
                ],
              );
            }
            final menus = snapshot.data ?? [];
            return ListView(
              padding: EdgeInsets.zero,
              children: [
                const DrawerHeader(
                  decoration: BoxDecoration(color: Colors.blue),
                  child: Text('Drawer Header'),
                ),
                ...menus.map((menu) => ListTile(
                      title: Text(menu.name),
                      onTap: () {
                        Navigator.pop(context);
                        // 自定义点击后的逻辑,比如跳转页面
                      },
                    )),
              ],
            );
          },
        ),
      ),
      body: const Center(child: Text('页面内容')),
    );
  }
}

注意事项

  • 确保已在pubspec.yaml中添加http依赖并执行flutter pub get:
dependencies:
  flutter:
    sdk: flutter
  http: ^1.1.0
  • 可根据需求扩展异常处理逻辑,比如无网络时的提示
  • 若菜单数据需要全局共享,可结合Provider、Bloc等状态管理工具实现

内容的提问来源于stack exchange,提问作者Mahsun Işık

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 06:54:23