利用PopupMenuButton
和PopupMenuItem
寫了個(gè)下拉選擇框冷冗,之所以不采用系統(tǒng)的,是因?yàn)樽远x的更能適配項(xiàng)目需求惑艇,話不多說蒿辙,直接看效果
gif.gif
下面直接貼出代碼、代碼中注釋寫的都很清楚滨巴,使用起來應(yīng)該很方便思灌,如果有任何問題,歡迎下方留言...
import 'package:flutter/material.dart';
class DropMenuWidget extends StatefulWidget {
final List<Map<String, dynamic>> data; //數(shù)據(jù)
final Function(String value) selectCallBack; //選中之后回調(diào)函數(shù)
final String? selectedValue; //默認(rèn)選中的值
final Widget? leading; //前面的widget恭取,一般是title
final Widget trailing; //尾部widget泰偿,一般是自定義圖片
final Color? textColor;
final Offset offset; //下拉框向下偏移量--手動(dòng)調(diào)整間距---防止下拉框遮蓋住顯示的widget
final TextStyle normalTextStyle; //下拉框的文字樣式
final TextStyle selectTextStyle; //下拉框選中的文字樣式
final double maxHeight; //下拉框的最大高度
final double maxWidth; //下拉框的最大寬度
final Color? backGroundColor; //下拉框背景顏色
final bool animation; //是否顯示動(dòng)畫---尾部圖片動(dòng)畫
final int duration; //動(dòng)畫時(shí)長
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,
});
@override
State<DropMenuWidget> createState() => _DropMenuWidgetState();
}
class _DropMenuWidgetState extends State<DropMenuWidget>
with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<double> _animation;
String _selectedLabel = '';
String _currentValue = '';
// 是否展開下拉按鈕
bool _isExpand = false;
@override
void 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,
),
);
}
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
_toggleExpand() {
setState(() {
if (_isExpand) {
_animationController.forward();
} else {
_animationController.reverse();
}
});
}
//根據(jù)傳值處理顯示的文字
_initLabel() {
if (_currentValue.isNotEmpty) {
_selectedLabel = widget.data
.firstWhere((item) => item['value'] == _currentValue)['label'];
} else if (widget.data.isNotEmpty) {
// 沒值默認(rèn)取第一個(gè)
_selectedLabel = widget.data[0]['label'];
_currentValue = widget.data[0]['value'];
}
}
@override
Widget 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是為了適配當(dāng)字符串長度超過指定寬度的時(shí)候,會(huì)讓字體自動(dòng)縮小
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度對應(yīng)的弧度值
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('當(dāng)前選中:'),
),
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', //默認(rèn)選中第三個(gè)
),
)
如果喜歡蜈垮,希望給個(gè)star???? CSDN地址