You need to enable JavaScript to run this app. Flutter中如何通过自定义_buildCard函数实现卡片点击页面跳转
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中如何通过自定义_buildCard函数实现卡片点击页面跳转

实现卡片点击跳转的可运行方案

首先明确:用普通函数构建Widget是Flutter里非常常见的写法,完全不需要硬改成自定义组件类。之前实现跳转一直报错,核心是跳转逻辑和函数参数没打通、加上卡片内部有星级评分组件导致的手势冲突,按下面的步骤调整即可,原有UI结构完全不用大改:

调整步骤

  • 给_buildCard方法新增一个VoidCallback onTap类型的入参,专门承接每张卡片独立的点击逻辑,避免在函数内部硬写Navigator导致的非法context引用报错
  • 把原来直接返回的Card包一层InkWell组件,把传入的onTap逻辑绑定到InkWell的点击回调上,自带点击水波纹效果,同时可以适配手势竞争规则
  • 在调用_buildCard的位置,给每张卡片传入对应的路由跳转逻辑即可

修改后的完整可运行代码

首先是调整后的_buildCard方法(原有UI逻辑完全保留,只新增点击绑定部分):

Widget _buildCard(int img, String text, int price, VoidCallback onTap) {
  return Card(
    // 给卡片绑定点击响应
    child: InkWell(
      onTap: onTap,
      child: Row(
        children: <Widget>[
          Container(
            margin: const EdgeInsets.all(8.0),
            width: 120.0,
            height: 180.0,
            decoration: BoxDecoration(
              image: DecorationImage(
                image: AssetImage("assets/$img.jpeg"),
                fit: BoxFit.cover,
              ),
              borderRadius: BorderRadius.circular(10.0),
            ),
          ),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: <Widget>[
                          Text(
                            text,
                            maxLines: 2,
                            textAlign: TextAlign.justify,
                            style: const TextStyle(
                                fontWeight: FontWeight.bold, fontSize: 22.0),
                          ),
                          const SizedBox(height: 5.0),
                          const Text(
                            "Janda Baik",
                            style: TextStyle(fontSize: 11.0, color: Colors.grey),
                          ),
                          const SizedBox(height: 5.0),
                          SmoothStarRating(
                            rating: rating,
                            isReadOnly: false,
                            size: 14,
                            filledIconData: Icons.star,
                            halfFilledIconData: Icons.star_half,
                            defaultIconData: Icons.star_border,
                            color: Colors.yellow,
                            starCount: 5,
                            allowHalfRating: true,
                            spacing: 2.0,
                            onRated: (value) {
                              print("rating value -> $value");
                            },
                          ),
                        ]),
                      Column(
                        children: <Widget>[
                          Text(
                            "\RM$price",
                            style: const TextStyle(
                                fontSize: 22.0, fontWeight: FontWeight.bold),
                          ),
                          const Text(
                            "per night",
                            style: TextStyle(fontSize: 11.0, color: Colors.grey),
                          )
                        ],
                      )
                    ],
                  ),
                )
              ],
            ),
          )
        ],
      ),
    ),
  );
}

然后是调用卡片的部分,把每个卡片对应的跳转逻辑直接作为参数传入:

_buildCard(
  3,
  "Azzahra\nVilla",
  1400,
  // Azzahra Villa 点击跳转逻辑
  () => Navigator.push(
    context,
    MaterialPageRoute(builder: (context) => const AzzahraVillaDetailPage()),
  ),
),
_buildCard(
  4,
  "Afsana\nVilla",
  1300,
  // Afsana Villa 点击跳转逻辑
  () => Navigator.push(
    context,
    MaterialPageRoute(builder: (context) => const AfsanaVillaDetailPage()),
  ),
),

常见报错排查说明

  • 之前如果报“无法找到已销毁组件的祖先节点”类的context错误,是因为直接在_buildCard内部硬写Navigator时,引用的context脱离了当前组件树,改成闭包传参的方式直接使用build方法内的合法context,就能彻底解决这个问题,不需要把函数改成自定义类
  • 如果点星级评分的位置时会同时触发卡片跳转,只需要在SmoothStarRating外层包一层带HitTestBehavior.opaque的GestureDetector,把星级组件的交互手势拦住,不让事件冒泡到上层的卡片点击区域即可
  • 顺带提一个现存的逻辑问题:当前定义的全局变量rating = 0.0是两个卡片共用的,任意一个卡片调整星级都会同步影响另一个的显示,建议给每个卡片单独维护对应的星级值,或者把星级组件设为只读展示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.03 23:45:02