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

Flutter中如何制作带动态Trailing的自定义Widget?

为不同页面自定义MyCard的Trailing按钮

要实现三个页面(全部电影、收藏电影、已删除电影)的MyCard显示不同的Trailing按钮布局,我们可以给MyCard添加页面类型标识,根据标识动态渲染对应的按钮组件。具体实现步骤如下:

1. 定义页面类型枚举

先创建一个枚举来区分三个页面的类型:

enum MoviePageType { allMovies, favMovies, deletedMovies }

2. 修改MyCard组件

更新MyCard的参数,添加页面类型、可选的删除和恢复回调,然后根据页面类型生成对应的Trailing按钮列表:

class MyCard extends StatelessWidget {
  final Movie e;
  final VoidCallback? taponfav;
  final VoidCallback? tapondel;
  final VoidCallback? taponRestore;
  final MoviePageType pageType;

  MyCard({
    required this.e,
    this.taponfav,
    this.tapondel,
    this.taponRestore,
    required this.pageType,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      child: ListTile(
        title: Text(e.name.toString()),
        subtitle: Text(e.language),
        trailing: _buildTrailingButtons(),
        leading: CircleAvatar(
          backgroundImage: NetworkImage(e.imageurl),
        ),
      ),
    );
  }

  Widget _buildTrailingButtons() {
    List<Widget> buttons = [];

    switch (pageType) {
      case MoviePageType.allMovies:
        // 全部电影页:显示收藏+删除按钮
        if (taponfav != null) {
          buttons.add(
            IconButton(
              icon: userlist[0].favmovies.contains(e)
                  ? const Icon(Icons.favorite)
                  : const Icon(Icons.favorite_outline),
              onPressed: taponfav,
            ),
          );
        }
        if (tapondel != null) {
          buttons.add(
            IconButton(
              icon: const Icon(Icons.delete),
              onPressed: tapondel,
            ),
          );
        }
        break;

      case MoviePageType.favMovies:
        // 收藏电影页:仅显示收藏按钮
        if (taponfav != null) {
          buttons.add(
            IconButton(
              icon: const Icon(Icons.favorite),
              onPressed: taponfav,
            ),
          );
        }
        break;

      case MoviePageType.deletedMovies:
        // 已删除电影页:显示恢复+永久删除按钮
        if (taponRestore != null) {
          buttons.add(
            IconButton(
              icon: const Icon(Icons.restore),
              onPressed: taponRestore,
            ),
          );
        }
        if (tapondel != null) {
          buttons.add(
            IconButton(
              icon: const Icon(Icons.delete_forever),
              onPressed: tapondel,
            ),
          );
        }
        break;
    }

    return Row(
      mainAxisSize: MainAxisSize.min,
      children: buttons,
    );
  }
}

3. 各页面使用MyCard示例

全部电影页

body: ListView(
  children: movielist
      .map((e) => MyCard(
            e: e,
            pageType: MoviePageType.allMovies,
            taponfav: () {
              if (userlist[0].favmovies.contains(e)) {
                userlist[0].favmovies.remove(e);
              } else {
                userlist[0].favmovies.add(e);
              }
              setState(() {});
            },
            tapondel: () {
              showDialog(
                context: context,
                builder: (ctx) {
                  return AlertDialog(
                    title: const Text('确定要删除吗?'),
                    actions: [
                      TextButton(
                        onPressed: () {
                          Navigator.of(ctx).pop();
                          userlist[0].deletedmovies.add(e);
                          movielist.remove(e);
                          setState(() {});
                          ScaffoldMessenger.of(context).showSnackBar(
                            SnackBar(
                              duration: const Duration(seconds: 4),
                              content: Text('${e.name} 已删除'),
                            ),
                          );
                        },
                        child: const Text('确定'),
                      ),
                      TextButton(
                        onPressed: () {
                          Navigator.of(ctx).pop();
                        },
                        child: const Text('取消'),
                      ),
                    ],
                  );
                },
              );
            },
          ))
      .toList(),
),

收藏电影页

body: ListView(
  children: userlist[0].favmovies
      .map((e) => MyCard(
            e: e,
            pageType: MoviePageType.favMovies,
            taponfav: () {
              userlist[0].favmovies.remove(e);
              setState(() {});
            },
          ))
      .toList(),
),

已删除电影页

body: ListView(
  children: userlist[0].deletedmovies
      .map((e) => MyCard(
            e: e,
            pageType: MoviePageType.deletedMovies,
            taponRestore: () {
              userlist[0].deletedmovies.remove(e);
              movielist.add(e);
              setState(() {});
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(
                  duration: const Duration(seconds: 4),
                  content: Text('${e.name} 已恢复'),
                ),
              );
            },
            tapondel: () {
              showDialog(
                context: context,
                builder: (ctx) {
                  return AlertDialog(
                    title: const Text('确定要永久删除吗?'),
                    actions: [
                      TextButton(
                        onPressed: () {
                          Navigator.of(ctx).pop();
                          userlist[0].deletedmovies.remove(e);
                          setState(() {});
                          ScaffoldMessenger.of(context).showSnackBar(
                            SnackBar(
                              duration: const Duration(seconds: 4),
                              content: Text('${e.name} 已永久删除'),
                            ),
                          );
                        },
                        child: const Text('确定'),
                      ),
                      TextButton(
                        onPressed: () {
                          Navigator.of(ctx).pop();
                        },
                        child: const Text('取消'),
                      ),
                    ],
                  );
                },
              );
            },
          ))
      .toList(),
),

通过以上修改,每个页面的MyCard会根据对应的类型渲染正确的Trailing按钮,同时保持组件的复用性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 21:36:29