如何将Flutter的PopupMenuItem封装到独立文件?解决类型转换异常
问题原因
你封装的MyWrappedMenuItem继承的是StatelessWidget,但PopupMenuButton<String>的itemBuilder要求返回的是List<PopupMenuEntry<String>>类型的列表。直接把MyWrappedMenuItem实例放进列表,相当于把Widget类型对象当成PopupMenuEntry<String>使用,类型不兼容,所以触发了类型转换错误。
修复方案
让封装类直接继承PopupMenuEntry<String>(而非StatelessWidget),这样它本身就是PopupMenuEntry类型,能直接被itemBuilder接受。
修正后的封装代码:
class MyWrappedMenuItem extends PopupMenuEntry<String> { final String title; final String? value; final IconData? icon; final void Function()? onTap; const MyWrappedMenuItem({ Key? key, required this.title, this.value, this.icon, this.onTap, }) : super(key: key); // 必须重写的属性,PopupMenuEntry强制要求 @override double get height => kMinInteractiveDimension; @override bool represents(String? value) => this.value == value; @override Widget build(BuildContext context) { return PopupMenuItem( value: value, child: ListTile( onTap: onTap, minLeadingWidth: 1, contentPadding: EdgeInsets.only(left: 0), title: Text(title, style: Theme.of(context).textTheme.subtitle1), leading: icon != null ? Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Icon( icon, size: 16, ), ], ) : null, ), ); } }
使用方式不变
原调用代码无需修改,直接使用即可:
PopupMenuButton<String>( itemBuilder: (context) => [MyWrappedMenuItem(title: 'title')], )
关键说明
- 继承
PopupMenuEntry<T>时,必须重写height和represents两个成员:height:定义菜单项高度,一般用系统默认的kMinInteractiveDimension即可represents:判断当前项是否匹配选中值,直接对比value即可
- 若坚持用
StatelessWidget封装,使用时需调用build方法返回PopupMenuEntry,示例:
但这种方式不够优雅,不推荐。PopupMenuButton<String>( itemBuilder: (context) => [MyWrappedMenuItem(title: 'title').build(context)], )
内容的提问来源于stack exchange,提问作者Farsen
相关产品推荐
相关产品推荐

