class CardWidget extends StatefulWidget {
final String title;
final Color color;
final IconData icon;
const CardWidget({
super.key,
required this.title,
required this.color,
required this.icon,
});
@override
State<CardWidget> createState() => _CardWidgetState();
}
class _CardWidgetState extends State<CardWidget> {
final List<String> items = [
'Key 1',
'Key 2',
'Key 3',
'Key 4',
];
String? selectedValue;
@override
Widget build(BuildContext context) {
return SizedBox(
height: 200,
width: 200,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
elevation: 10,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
color: widget.color,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Icon(
widget.icon,
color: Colors.white,
size: 32,
),
Center(
child: Text(
widget.title,
style: GoogleFonts.poppins(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.bold),
),
),
DropdownButtonHideUnderline(
child: DropdownButton2(
isExpanded: true,
hint: Row(
children: [
Expanded(
child: Center(
child: Text(
'Select a Key',
style: dropdownTitle,
overflow: TextOverflow.ellipsis,
),
),
),
],
),
items: items
.map((item) => DropdownMenuItem<String>(
value: item,
child: Center(
child: Text(
item,
style: dropdownItems,
overflow: TextOverflow.ellipsis,
),
),
))
.toList(),
value: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value as String;
});
},
icon: const Icon(
Icons.arrow_forward_ios_outlined,
),
iconSize: 20,
iconEnabledColor: Color.fromARGB(255, 31, 10, 88),
iconDisabledColor: Colors.grey,
buttonHeight: 40,
buttonWidth: 135,
buttonPadding: const EdgeInsets.only(
left: 15,
right: 15,
),
buttonDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(14),
border: Border.all(
color: Colors.black26,
),
color: Color.fromARGB(255, 255, 255, 255),
),
buttonElevation: 2,
itemHeight: 40,
itemPadding: const EdgeInsets.only(left: 14, right: 14),
dropdownMaxHeight: 200,
dropdownWidth: 200,
dropdownPadding: null,
dropdownDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white,
),
dropdownElevation: 8,
scrollbarRadius: const Radius.circular(10),
scrollbarThickness: 6,
scrollbarAlwaysShow: true,
offset: const Offset(-20, 0),
),
),
CardWidget, который я создал.
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
CardWidget(
title: 'Mute',
color: Color.fromARGB(255, 211, 38, 25),
icon: Icons.volume_off_outlined,
),
CardWidget(
title: 'Mute',
color: Color.fromARGB(255, 211, 38, 25),
icon: Icons.volume_off_outlined,
),
CardWidget(
title: 'Mute',
color: Color.fromARGB(255, 211, 38, 25),
icon: Icons.volume_off_outlined,
),
CardWidget(
title: 'Mute',
color: Color.fromARGB(255, 211, 38, 25),
icon: Icons.volume_off_outlined,
),
],
),
Домашняя страница, на которой я использую CardWidget.
Я могу вызвать свой список и выбрать элементы внутри списка.
Однако, как видно на изображении, он может быть активным, даже если во всех раскрывающихся списках выбрана «клавиша 1». Я имею дело, например, с тем, что «ключ 1» выбран в первом раскрывающемся списке, если «ключ 1» выбран во втором раскрывающемся списке, он просто покажет его там. Во втором раскрывающемся списке не должно быть написано «ключ 1» под меню, оно должно быть написано в последнем выбранном. Оставьте первое поле пустым.
Я использую pub.dev/packages/dropdown_button2 этот пакет.
Можете ли вы включить образец тела лесов со всеми. кажется его не хватает
Я добавил весь свой код.
На эшафоте будет 5 дропдаунов?
Будет 4 штуки. Я показал, как определил один виджет CardWidget на главной странице, чтобы не писать тот же код. Как и на втором фото, есть дизайн карты с 4 выпадающими меню рядом. Есть выпадающие с ключевыми номерами от 1 до 4 каждый.
Просто добавьте CardWidget 4 раза, и он отобразит изображение на второй фотографии.
Я снова отредактировал свой код.
Хорошо, понял, позвольте мне посмотреть, что я могу сделать для вас
Вопрос супер крутой
Я пытался в течение 3-4 часов, но я не мог найти ответ.
Я начал с карты, но это было немного хаотично для понимания другими, а затем преобразовать в класс модели, чтобы сделать его читабельным.
Удален выбранный элемент из раскрывающегося списка других: Я использую Valunotifer для упрощения фрагмента, и логика
onChanged: (value) {
final index =
cardsNotifier.value.indexWhere((element) => element.id == id);
for (int i = 0; i < cardsNotifier.value.length; i++) {
if (index != i && cardsNotifier.value[i].selectedItem == value) {
cardsNotifier.value[i].selectedItem = null;
}
}
cardsNotifier.value[index].selectedItem = value;
cardsNotifier.value = cardsNotifier.value.toList();
},
Тестовый виджет
class FA extends StatefulWidget {
const FA({super.key});
@override
State<FA> createState() => _FAState();
}
class CardHelper {
final int id;
String? selectedItem;
CardHelper({
required this.id,
this.selectedItem,
});
}
ValueNotifier<List<CardHelper>> cardsNotifier = ValueNotifier(List.generate(
4,
(index) => CardHelper(
id: index,
)));
class _FAState extends State<FA> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(children: [
for (int i = 0; i < cardsNotifier.value.length; i++)
CardWidget(
title: 'Mute',
id: cardsNotifier.value[i].id,
),
]),
);
}
}
class CardWidget extends StatelessWidget {
final String title;
final int id;
const CardWidget({
super.key,
required this.id,
required this.title,
});
@override
Widget build(BuildContext context) {
return SizedBox(
height: 200,
width: 200,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
elevation: 10,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
itemBuilder(),
],
),
),
),
);
}
ValueListenableBuilder<List<CardHelper>> itemBuilder() {
return ValueListenableBuilder<List<CardHelper>>(
valueListenable: cardsNotifier,
builder: (context, data, child) => DropdownButtonHideUnderline(
child: DropdownButton2(
isExpanded: true,
hint: Row(
children: [
Expanded(
child: Center(
child: Text(
'Select a Key',
overflow: TextOverflow.ellipsis,
),
),
),
],
),
items: ['Key 1', 'Key 2', 'Key 3', 'Key 4']
.map((item) => DropdownMenuItem<String>(
value: item,
child: Center(
child: Text(
item,
overflow: TextOverflow.ellipsis,
),
),
))
.toList(),
value: data[id].selectedItem,
onChanged: (value) {
final index =
cardsNotifier.value.indexWhere((element) => element.id == id);
for (int i = 0; i < cardsNotifier.value.length; i++) {
if (index != i && cardsNotifier.value[i].selectedItem == value) {
cardsNotifier.value[i].selectedItem = null;
}
}
cardsNotifier.value[index].selectedItem = value;
cardsNotifier.value = cardsNotifier.value.toList();
},
icon: const Icon(
Icons.arrow_forward_ios_outlined,
),
iconSize: 20,
),
),
);
}
}
Удалить выбранный элемент из выпадающего списка
Я использую вспомогательный класс для упрощения
class CardHelper {
final int id;
final List<String> items;
final String? selectedItem;
CardHelper({
required this.id,
required this.items,
this.selectedItem,
});
}
А виджет CardWidget
принимает данные в качестве входных данных и обеспечивает обратный вызов с выбранным элементом.
class CardWidget extends StatefulWidget {
final List<String> items;
final Function(String?) selectedItemCallback;
.....
const CardWidget({
super.key,
required this.items,
И onChanged будет
items: widget.items
.map((item) => DropdownMenuItem<String>(
value: item,
child: Center(
child: Text(
item,
overflow: TextOverflow.ellipsis,
),
),
))
.toList(),
value: selectedValue,
onChanged: (value) {
widget.selectedItemCallback(value);
Теперь для родительского виджета мы создадим список для карт
final cards = List.generate(
4,
(index) =>
CardHelper(id: index, items: ['Key 1', 'Key 2', 'Key 3', 'Key 4']));
И остальная логика лежит
for (int i = 0; i < cards.length; i++)
CardWidget(
title: 'Mute',
color: Color.fromARGB(255, 211, 38, 25),
icon: Icons.volume_off_outlined,
items: cards[i].items,
selectedItemCallback: (p0) {
for (int j = 0; j < cards.length; j++) {
if (i == j) continue;
cards[j].items.remove(p0);
}
setState(() {});
},
),
Воспроизвести виджет
void main(List<String> args) {
runApp(MaterialApp(home: FA()));
}
class FA extends StatefulWidget {
const FA({super.key});
@override
State<FA> createState() => _FAState();
}
class CardHelper {
final int id;
final List<String> items;
final String? selectedItem;
CardHelper({
required this.id,
required this.items,
this.selectedItem,
});
}
class _FAState extends State<FA> {
final cards = List.generate(
4,
(index) =>
CardHelper(id: index, items: ['Key 1', 'Key 2', 'Key 3', 'Key 4']));
@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: [
for (int i = 0; i < cards.length; i++)
CardWidget(
title: 'Mute',
color: Color.fromARGB(255, 211, 38, 25),
icon: Icons.volume_off_outlined,
items: cards[i].items,
selectedItemCallback: (p0) {
for (int j = 0; j < cards.length; j++) {
if (i == j) continue;
cards[j].items.remove(p0);
}
setState(() {});
},
),
],
),
);
}
}
class CardWidget extends StatefulWidget {
final List<String> items;
final String title;
final Color color;
final IconData icon;
final Function(String?) selectedItemCallback;
const CardWidget({
super.key,
required this.items,
required this.title,
required this.color,
required this.icon,
required this.selectedItemCallback,
});
@override
State<CardWidget> createState() => _CardWidgetState();
}
class _CardWidgetState extends State<CardWidget> {
String? selectedValue;
@override
Widget build(BuildContext context) {
return SizedBox(
height: 200,
width: 200,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
elevation: 10,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
color: widget.color,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Icon(
widget.icon,
color: Colors.white,
size: 32,
),
Center(
child: Text(
widget.title,
),
),
DropdownButtonHideUnderline(
child: DropdownButton2(
isExpanded: true,
hint: Row(
children: [
Expanded(
child: Center(
child: Text(
'Select a Key',
overflow: TextOverflow.ellipsis,
),
),
),
],
),
items: widget.items
.map((item) => DropdownMenuItem<String>(
value: item,
child: Center(
child: Text(
item,
overflow: TextOverflow.ellipsis,
),
),
))
.toList(),
value: selectedValue,
onChanged: (value) {
widget.selectedItemCallback(value);
setState(() {
selectedValue = value as String;
});
},
icon: const Icon(
Icons.arrow_forward_ios_outlined,
),
iconSize: 20,
iconEnabledColor: Color.fromARGB(255, 31, 10, 88),
iconDisabledColor: Colors.grey,
buttonHeight: 40,
buttonWidth: 135,
buttonPadding: const EdgeInsets.only(
left: 15,
right: 15,
),
buttonDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(14),
border: Border.all(
color: Colors.black26,
),
color: Color.fromARGB(255, 255, 255, 255),
),
buttonElevation: 2,
itemHeight: 40,
itemPadding: const EdgeInsets.only(left: 14, right: 14),
dropdownMaxHeight: 200,
dropdownWidth: 200,
dropdownPadding: null,
dropdownDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white,
),
dropdownElevation: 8,
scrollbarRadius: const Radius.circular(10),
scrollbarThickness: 6,
scrollbarAlwaysShow: true,
offset: const Offset(-20, 0),
),
),
],
),
),
),
);
}
}
Также есть опция enabled
на DropdownMenuItem
, которая может отключать состояние с отображением элементов.
Очень удачное решение. Большое спасибо. Но где-то есть проблема. Например, допустим, для первой карты выбран ключ 1. Ключ 1 должен появиться на второй карточке. Если пользователь выбирает ключ 1 для второй карты, ключ 1 теперь должен быть записан под второй картой. Но с этим кодом я могу выбрать только 1 ключ один раз.
вы хотите переопределить значение, если пользователь выбирает 1-й ключ во втором поле, которое выбирается?
Нет, я хочу, чтобы все значения были действительны во всех выпадающих списках. Если пользователь выбирает «ключ 1» на первой карточке и хочет выбрать «ключ 1» на второй карточке, ключ 1 на первой карточке следует удалить вместо текста по умолчанию «выберите ключ» или он должен быть пустым.
хорошо, последний выбранный будет иметь приоритет, я думаю, у меня есть?
я скоро до тебя доберусь
Да, вы правильно думаете. Я жду вашего ответа. Большое спасибо.
Обновлено, занят финалом семестра 😅
Хорошо. Желаю вам успехов на экзаменах.
тестовая часть обновления (вверху), которая должна ответить на ваш пост
Большое спасибо, это именно то решение, которое я хотел. Я просто хочу кое-что спросить. Например, поскольку заголовок созданного вами cardWidget находится в цикле for, он присваивает всем этим карточкам заголовок «Mute». Но названия каждой из этих карт я дам отдельно. Как я могу это сделать?
Вы можете составить список, а затем передать как muteList[i]
, или лучше создать поле в классе модели
вы используете какой-то пакет для DropdownButtonWidget