利用PopupMenuButton
和PopupMenuItem
写了个下拉选择框,之所以不采用系统的,是因为自定义的更能适配项目需求,话不多说,直接看效果
下面直接贴出代码、代码中注释写的都很清楚,使用起来应该很方便,如果有任何问题,欢迎下方留言…
import 'package:flutter/material.dart';class DropMenuWidget extends StatefulWidget {final List<Map<String, dynamic>> data; //数据final Function(String value) selectCallBack; //选中之后回调函数final String? selectedValue; //默认选中的值final Widget? leading; //前面的widget,一般是titlefinal Widget trailing; //尾部widget,一般是自定义图片final Color? textColor;final Offset offset; //下拉框向下偏移量--手动调整间距---防止下拉框遮盖住显示的widgetfinal TextStyle normalTextStyle; //下拉框的文字样式final TextStyle selectTextStyle; //下拉框选中的文字样式final double maxHeight; //下拉框的最大高度final double maxWidth; //下拉框的最大宽度final Color? backGroundColor; //下拉框背景颜色final bool animation; //是否显示动画---尾部图片动画final int duration; //动画时长const DropMenuWidget({super.key,this.leading,required this.data,required this.selectCallBack,this.selectedValue,this.trailing = const Icon(Icons.arrow_drop_down),this.textColor = Colors.white,this.offset = const Offset(0, 30),this.normalTextStyle = const TextStyle(color: Colors.white,fontSize: 12.0,),this.selectTextStyle = const TextStyle(color: Colors.red,fontSize: 12.0,),this.maxHeight = 200.0,this.maxWidth = 200.0,this.backGroundColor = const Color.fromRGBO(28, 34, 47, 1),this.animation = true,this.duration = 200,});@overrideState<DropMenuWidget> createState() => _DropMenuWidgetState();
}class _DropMenuWidgetState extends State<DropMenuWidget>with SingleTickerProviderStateMixin {late AnimationController _animationController;late Animation<double> _animation;String _selectedLabel = '';String _currentValue = '';// 是否展开下拉按钮bool _isExpand = false;@overridevoid initState() {super.initState();_currentValue = widget.selectedValue ?? '';if (widget.animation) {_animationController = AnimationController(vsync: this,duration: Duration(milliseconds: widget.duration),);_animation = Tween(begin: 0.0, end: 0.5).animate(CurvedAnimation(parent: _animationController,curve: Curves.easeInOut,),);}}@overridevoid dispose() {_animationController.dispose();super.dispose();}_toggleExpand() {setState(() {if (_isExpand) {_animationController.forward();} else {_animationController.reverse();}});}//根据传值处理显示的文字_initLabel() {if (_currentValue.isNotEmpty) {_selectedLabel = widget.data.firstWhere((item) => item['value'] == _currentValue)['label'];} else if (widget.data.isNotEmpty) {// 没值默认取第一个_selectedLabel = widget.data[0]['label'];_currentValue = widget.data[0]['value'];}}@overrideWidget build(BuildContext context) {_initLabel();return PopupMenuButton(constraints: BoxConstraints(maxHeight: widget.maxHeight,maxWidth: widget.maxWidth,),shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4.0),),offset: widget.offset,color: widget.backGroundColor,onOpened: () {if (widget.animation) {setState(() {_isExpand = true;_toggleExpand();});}},onCanceled: () {if (widget.animation) {setState(() {_isExpand = false;_toggleExpand();});}},child: Container(alignment: Alignment.centerLeft,height: 40,child: FittedBox(//使用FittedBox是为了适配当字符串长度超过指定宽度的时候,会让字体自动缩小child: Row(children: [if (widget.leading != null) widget.leading!,Text(_selectedLabel,style: TextStyle(color: widget.textColor,fontSize: 14.0,),),if (widget.animation)AnimatedBuilder(animation: _animation,builder: (context, child) {return Transform.rotate(angle: _animation.value * 2.0 * 3.14, // 180度对应的弧度值child: widget.trailing,);},),if (!widget.animation) widget.trailing,],),),),itemBuilder: (context) {return widget.data.map((e) {return PopupMenuItem(child: Text(e['label'],style: e['value'] == _currentValue? widget.selectTextStyle: widget.normalTextStyle,),onTap: () {setState(() {_currentValue = e['value'];widget.selectCallBack(e['value']);});},);}).toList();},);}
}
使用
Container(color: Colors.grey,width: 130,alignment: Alignment.centerLeft,child: DropMenuWidget(leading: const Padding(padding: EdgeInsets.only(right: 10),child: Text('当前选中:'),),data: const [{'label': '华为', 'value': '1'},{'label': '小米', 'value': '2'},{'label': 'Apple', 'value': '3'},{'label': '乔布斯', 'value': '4'},{'label': '啦啦啦啦啦', 'value': '5'},{'label': '呵呵', 'value': '7'},{'label': '乐呵乐呵', 'value': '7'},],selectCallBack: (value) {print('选中的value是:$value');},offset: const Offset(0, 40),selectedValue: '3', //默认选中第三个),)
简书地址如果喜欢,希望给个star😄😄