我想創建自定義下拉按鈕,如下所示:-
我嘗試了很多解決方案,但我無法找到任何方法來做到這一點
uj5u.com熱心網友回復:
使用此代碼來實作您的結果:-
我在@masum billah sanjid 的幫助下找到了這個
class CustDropDown<T> extends StatefulWidget {
final List<CustDropdownMenuItem> items;
final Function onChanged;
final String hintText;
final double borderRadius;
final double maxListHeight;
final double borderWidth;
final int defaultSelectedIndex;
final bool enabled;
const CustDropDown(
{required this.items,
required this.onChanged,
this.hintText = "",
this.borderRadius = 0,
this.borderWidth = 1,
this.maxListHeight = 100,
this.defaultSelectedIndex = -1,
Key? key,
this.enabled = true})
: super(key: key);
@override
_CustDropDownState createState() => _CustDropDownState();
}
class _CustDropDownState extends State<CustDropDown>
with WidgetsBindingObserver {
bool _isOpen = false, _isAnyItemSelected = false, _isReverse = false;
late OverlayEntry _overlayEntry;
late RenderBox? _renderBox;
Widget? _itemSelected;
late Offset dropDownOffset;
final LayerLink _layerLink = LayerLink();
@override
void initState() {
WidgetsBinding.instance!.addPostFrameCallback((_) {
if (mounted) {
setState(() {
dropDownOffset = getOffset();
});
}
if (widget.defaultSelectedIndex > -1) {
if (widget.defaultSelectedIndex < widget.items.length) {
if (mounted) {
setState(() {
_isAnyItemSelected = true;
_itemSelected = widget.items[widget.defaultSelectedIndex];
widget.onChanged(widget.items[widget.defaultSelectedIndex].value);
});
}
}
}
});
WidgetsBinding.instance!.addObserver(this);
super.initState();
}
void _addOverlay() {
if (mounted) {
setState(() {
_isOpen = true;
});
}
_overlayEntry = _createOverlayEntry();
Overlay.of(context)!.insert(_overlayEntry);
}
void _removeOverlay() {
if (mounted) {
setState(() {
_isOpen = false;
});
_overlayEntry.remove();
}
}
@override
dispose() {
WidgetsBinding.instance!.removeObserver(this);
super.dispose();
}
OverlayEntry _createOverlayEntry() {
_renderBox = context.findRenderObject() as RenderBox?;
var size = _renderBox!.size;
dropDownOffset = getOffset();
return OverlayEntry(
maintainState: false,
builder: (context) => Align(
alignment: Alignment.center,
child: CompositedTransformFollower(
link: _layerLink,
showWhenUnlinked: false,
offset: dropDownOffset,
child: SizedBox(
height: widget.maxListHeight,
width: size.width,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: _isReverse
? MainAxisAlignment.end
: MainAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 10),
child: Container(
constraints: BoxConstraints(
maxHeight: widget.maxListHeight,
maxWidth: size.width),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12)),
child: ClipRRect(
borderRadius: BorderRadius.all(
Radius.circular(widget.borderRadius),
),
child: Material(
elevation: 0,
shadowColor: Colors.grey,
child: ListView(
padding: EdgeInsets.zero,
shrinkWrap: true,
children: widget.items
.map((item) => GestureDetector(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: item.child,
),
onTap: () {
if (mounted) {
setState(() {
_isAnyItemSelected = true;
_itemSelected = item.child;
_removeOverlay();
if (widget.onChanged != null)
widget.onChanged(item.value);
});
}
},
))
.toList(),
),
),
),
),
),
],
),
),
),
));
}
Offset getOffset() {
RenderBox? renderBox = context.findRenderObject() as RenderBox?;
double y = renderBox!.localToGlobal(Offset.zero).dy;
double spaceAvailable = _getAvailableSpace(y renderBox.size.height);
if (spaceAvailable > widget.maxListHeight) {
_isReverse = false;
return Offset(0, renderBox.size.height);
} else {
_isReverse = true;
return Offset(
0,
renderBox.size.height -
(widget.maxListHeight renderBox.size.height));
}
}
double _getAvailableSpace(double offsetY) {
double safePaddingTop = MediaQuery.of(context).padding.top;
double safePaddingBottom = MediaQuery.of(context).padding.bottom;
double screenHeight =
MediaQuery.of(context).size.height - safePaddingBottom - safePaddingTop;
return screenHeight - offsetY;
}
@override
Widget build(BuildContext context) {
return CompositedTransformTarget(
link: _layerLink,
child: GestureDetector(
onTap: widget.enabled
? () {
_isOpen ? _removeOverlay() : _addOverlay();
}
: null,
child: Container(
decoration: _getDecoration(),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Flexible(
flex: 3,
child: _isAnyItemSelected
? Padding(
padding: const EdgeInsets.only(left: 4.0),
child: _itemSelected!,
)
: Padding(
padding:
const EdgeInsets.only(left: 4.0), // change it here
child: Text(
widget.hintText,
maxLines: 1,
overflow: TextOverflow.clip,
),
),
),
const Flexible(
flex: 1,
child: Icon(
Icons.arrow_drop_down,
),
),
],
),
),
),
);
}
Decoration? _getDecoration() {
if (_isOpen && !_isReverse) {
return BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(widget.borderRadius),
topRight: Radius.circular(
widget.borderRadius,
)));
} else if (_isOpen && _isReverse) {
return BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(widget.borderRadius),
bottomRight: Radius.circular(
widget.borderRadius,
)));
} else if (!_isOpen) {
return BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(widget.borderRadius)));
}
}
}
class CustDropdownMenuItem<T> extends StatelessWidget {
final T value;
final Widget child;
const CustDropdownMenuItem({required this.value, required this.child});
@override
Widget build(BuildContext context) {
return child;
}
}
像這樣在您的用戶界面中使用它:-
class DropDownTest extends StatelessWidget {
const DropDownTest({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF2F3F7),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Container(
width: 200,
height: 40,
decoration: BoxDecoration(
color: Colors.white, borderRadius: BorderRadius.circular(12)),
child: CustDropDown(
items: const [
CustDropdownMenuItem(
value: 0,
child: Text("Day"),
),
CustDropdownMenuItem(
value: 0,
child: Text("Week"),
)
],
hintText: "DropDown",
borderRadius: 5,
onChanged: (val) {
print(val);
},
),
),
)
],
),
);
}
}
uj5u.com熱心網友回復:
您可以使用DropdownButton2自定義它以及更多。它基于 Flutter 的核心 DropdownButton ,您可以根據需要自定義更多選項。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/408275.html
標籤:
上一篇:如何將針旋轉半圓?
