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
相关产品推荐
相关产品推荐

