'Flutter DropdownButton - Add title for separating items
Im trying to implement a DropdownButton
that can separate specific items from each other with a title (see desired output on image below, the titles are in green)
Like in the example I would like to add these green titles to my existing DropdownButton
, but did not find anything that showed me how to add something else than items to a DropdownButton
I also tried to switch from DropdownButton
to a ListView
with ExpansionTile
but I would like to keep the behaviour of the DropdownButton
...
Is it possible to add these titles to the DropdownButton
items
? Or shourd I try to achive it by a other way? Im stuck at the moment and dont know how to proceed
Solution 1:[1]
try this code in dartpad:
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
home: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return HomeScreen();
}
}
class HomeScreen extends StatefulWidget {
@override
HomeScreenState createState() => HomeScreenState();
}
class HomeScreenState extends State<HomeScreen> {
String dropdownValue;
List<Product> products = [
Product(name: 'sep1', type: 'sep'),
Product(name: 'milk', type: 'data'),
Product(name: 'oil', type: 'data'),
Product(name: 'sep2', type: 'sep'),
Product(name: 'suger', type: 'data'),
Product(name: 'salt', type: 'data'),
Product(name: 'sep3', type: 'sep'),
Product(name: 'potatoe', type: 'data'),
Product(name: 'tomatoe', type: 'data'),
Product(name: 'apple', type: 'data'),
];
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('text')),
body: Column(
children: [
Text('test'),
Expanded(
child: DropdownButton<String>(
value: dropdownValue,
items: products.map((value) {
return DropdownMenuItem(
value: value.name,
child: value.type == 'data'
? Text(value.name)
: Divider(
color: Colors.red,
thickness: 3,
),
);
}).toList(),
onChanged: (newValue) {
setState(() {
dropdownValue = newValue;
});
print('$newValue $dropdownValue');
},
),
),
],
),
);
}
}
class Product {
String name;
String type;
Product({this.name, this.type});
}
Solution 2:[2]
In addition to Ali Tenni's answer you can also subclass DropdownMenuItem
like this:
class DropdownMenuItemSeparator<T> extends DropdownMenuItem<T> {
DropdownMenuItemSeparator() : super(
enabled: false, // As of Flutter 2.5.
child: Container(), // Trick the assertion.
);
@override
Widget build(BuildContext context) {
return Divider(thickness: 3);
}
}
This will make the separator more narrow because otherwise the default build()
adds some min height.
UPD 2021-09-14 Below is no longer relevant as the feature is implemented in Flutter 2.5. The code above updated accordingly.
This solves one of the two problems. Unfortunately, the second and the larger problem is that the separator is still tappable, and the tap closes the dropdown. To address this, I submitted a feature request to Flutter: https://github.com/flutter/flutter/issues/75487
Solution 3:[3]
This is my code from a closed question: How to create a dropdown menu with sections?
The y position of the accepted anwser change. I don't understand why it's an accepted anwser.
import 'package:flutter/material.dart';
class CustomDropDownMenu extends StatefulWidget {
final Widget child;
const CustomDropDownMenu({Key? key, required this.child}) : super(key: key);
@override
_CustomDropDownMenu createState() => _CustomDropDownMenu();
}
class _CustomDropDownMenu extends State<CustomDropDownMenu>
with SingleTickerProviderStateMixin {
OverlayEntry? overlayEntry;
late AnimationController _animationController;
@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this, duration: const Duration(milliseconds: 500));
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MouseRegion(
onExit: (onExit) {
setOnExitMenu(context, onExit.delta.dy);
},
child: GestureDetector(
onTap: () {
insertOverlay(context);
_animationController.forward();
},
child: widget.child),
);
}
void setOnExitMenu(BuildContext context, double delta) {
if (delta >= 0) {
return;
}
closeDropDown();
}
void insertOverlay(BuildContext context) {
closeDropDown();
final rect = findParamsData(context);
overlayEntry = _createOverlay(rect: rect);
Overlay.of(context)!.insert(overlayEntry!);
}
OverlayEntry _createOverlay({required Rect rect}) {
return OverlayEntry(builder: (context) {
return Material(
color: Colors.transparent,
child: Stack(
alignment: Alignment.center,
clipBehavior: Clip.none,
children: [
Positioned(
child: IgnorePointer(
child: Container(
color: Colors.black45,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
),
),
),
Positioned.fromRect(
rect: Rect.fromLTWH(
rect.left, rect.top, rect.width * 3, rect.height * 10),
child: SlideTransition(
position: Tween(
begin: const Offset(0, 0.15),
end: const Offset(0, 0))
.animate(_animationController),
child: MouseRegion(
onExit: (onExit) {
setOnExitMenu(context, -1);
},
child: const ContentDropDown(),
)
)),
],
),
);
});
}
Rect findParamsData(BuildContext context) {
final RenderBox renderBox = context.findRenderObject()! as RenderBox;
final size = renderBox.size;
final offset = renderBox.localToGlobal(Offset.zero);
return Rect.fromLTWH(
offset.dx, offset.dy + size.height, size.width, size.height);
}
void closeDropDown() {
if (overlayEntry != null) {
overlayEntry!.remove();
overlayEntry = null;
}
}
}
class ContentDropDown extends StatelessWidget {
const ContentDropDown({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Theme.of(context).colorScheme.secondary,
width: 0.5)),
child: ListView(
shrinkWrap: true,
children: [
TextFormField(),
ListView.builder(
shrinkWrap: true,
itemCount: 10,
itemBuilder: (context, index) {
return ListTile(
leading: Image.network(
"https://upload.wikimedia.org/wikipedia/nap/thumb/f/f3/Logo_UEFA_Champions_League.png/250px-Logo_UEFA_Champions_League.png"),
title: const Text("Champions League"),
);
}),
],
),
);
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Ali Tenni |
Solution 2 | |
Solution 3 | mario francois |