to create the popup list i used 
button bottom
I chose all possible methods in the library, but still I can't use it with the addition of a button
all code https://github.com/dimapichuev2000/test_dropdownbutton
main.dart
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:dropdown_search/dropdown_search.dart';
import 'package:test_dropdownbutton/gym_model.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData().copyWith(
primaryColor: Colors.amber,
colorScheme: ThemeData().colorScheme.copyWith(
primary: Colors.orange,
),
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _multiKey = GlobalKey<DropdownSearchState<String>>();
Widget _customDropDownExample(BuildContext context, GymModel? item) {
if (item == null) {
return const Text(
"Выберите фитнесс центр",
style:
TextStyle(fontSize: 15, color: Color.fromRGBO(33, 33, 33, 0.6)),
);
}
return Container(
child: (item.avatar == "")
? ListTile(
contentPadding: EdgeInsets.all(0),
leading: const CircleAvatar(
radius: 25,
backgroundColor: Colors.white,
backgroundImage: NetworkImage(
'https://img.icons8.com/ios/50/000000/gum-.png'),
),
title: Text(item.gym),
subtitle: Text(
item.location,
),
)
: ListTile(
contentPadding: const EdgeInsets.all(0),
leading: CircleAvatar(
radius: 25,
backgroundImage: NetworkImage(item.avatar ?? ''),
),
title: Text(item.gym),
subtitle: Text(
item.location,
),
),
);
}
Widget _exitPopup(BuildContext context) {
return Container(
decoration: const BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
padding: const EdgeInsets.only(top: 2),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
margin: EdgeInsets.all(8),
height: 30,
width: 30,
),
const Text(
"Фитнесс центр",
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w500),
),
IconButton(
icon: Image.asset(
'assets/button_X.png',
width: 25,
height: 25,
fit: BoxFit.fill,
),
iconSize: 25,
onPressed: () {
Navigator.of(context).pop();
},
)
],
),
);
}
Widget _customPopupItemBuilderExample(
BuildContext context, GymModel? item, bool isSelected) {
return Container(
decoration: !isSelected
? null
: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.white,
),
child: ListTile(
selected: isSelected,
title: Text(item?.gym ?? ''),
subtitle: Text(item?.location ?? ''),
leading: (item!.avatar == "")
? const CircleAvatar(
radius: 25,
backgroundColor: Colors.white,
backgroundImage: NetworkImage(
'https://img.icons8.com/ios/100/000000/gum-.png'),
)
: CircleAvatar(
radius: 25,
backgroundImage: NetworkImage(item.avatar ?? ''),
)),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Key value Pair - DropdownButton'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Container(
margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
child: SingleChildScrollView(
child: DropdownSearch<GymModel>(
mode: Mode.BOTTOM_SHEET,
showSearchBox: true,
compareFn: (item, selectedItem) => item?.id == selectedItem?.id,
scrollbarProps:ScrollbarProps(
radius: Radius.circular(20),
thickness: 4,
),
onFind: (String? filter) => getData(filter),
dropdownSearchDecoration: const InputDecoration(
filled: true,
fillColor: Color(0xFFE3E3E4),
hintText: "Выберите фитнесс центр",
border: OutlineInputBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10),
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10),
),
borderSide: BorderSide(
width: 0,
style: BorderStyle.none,
),
),
contentPadding: EdgeInsets.fromLTRB(12, 3, 0, 0),
),
popupSafeArea:
const PopupSafeAreaProps(top: true, bottom: true),
// labelText: "Выберите фитнесс центр ",
onChanged: (data) {
print(data);
},
maxHeight: 850,
dropdownBuilder: _customDropDownExample,
popupItemBuilder: _customPopupItemBuilderExample,
dropDownButton: Image.asset('assets/dropButton.png',
color: Color(0xFF79818A)),
popupTitle: _exitPopup(context),
popupShape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10),
),
),
searchFieldProps: TextFieldProps(
decoration: const InputDecoration(
prefixIcon: Icon(
Icons.search,
),
filled: true,
fillColor: Color(0xFFE3E3E4),
border: OutlineInputBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10),
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10),
),
borderSide: BorderSide(
width: 0,
style: BorderStyle.none,
),
),
contentPadding: EdgeInsets.fromLTRB(12, 12, 8,0),
// labelText: "Поиск",
hintText: "Поиск",
hintStyle: TextStyle(fontSize: 17)),
),
),
),
),
],
),
),
);
}
Future<List<GymModel>> getData(filter) async {
var response = await Dio().get(
"https://my-json-server.typicode.com/dimapichuev2000/JSON_TEST/posts",
queryParameters: {"filter": filter},
);
final data = response.data;
if (data != null) {
return GymModel.fromJsonList(data);
}
return [];
}
}
gym_model.dart
class GymModel {
final String id;
final String location;
final String gym;
final String? avatar;
GymModel(
{required this.id,
required this.location,
required this.gym,
this.avatar});
factory GymModel.fromJson(Map<String, dynamic> json) {
return GymModel(
id: json["id"],
location: json["location"],
gym: json["gym"],
avatar: json["avatar"],
);
}
static List<GymModel> fromJsonList(List list) {
return list.map((item) => GymModel.fromJson(item)).toList();
}
@override
String toString() => gym;
}
my english is not very good please be understanding
CodePudding user response:
There are many ways you can do that but the easiest and the most elegant solution in my opinion is the following:
Column(
children: [
Flexible(
child: ListView.builder(
shrinkWrap: true,
itemCount: 5,
itemBuilder: (BuildContext context, int i) {
return Text(i.toString());
},
),
),
ElevatedButton.icon(
onPressed: null,
icon: const Icon(Icons.abc),
label: const Text('next')),
],
);
Start with a Column widget and then add ListView.builder and button of your choosing, I use ElevatedButton.icon, as it's children. Now set the shrinkWrap setting in ListView.builder to true and finally wrap it with Flexible widget.
In your case, you can wrap your Container widget with a ListView.builder widget and if you get viewport.dart error just wrap it with either Flexible or Expanded, depending on how much space you want it to consume. Then you can add logic to check if you are at the last index, in which case you can show your button, this is kinda what the code it will end up looking like:
Flexible(
child: ListView.builder(
shrinkWrap: true,
itemCount: _listSavedOutsideThisWidget.length 1,
itemBuilder: (BuildContext context, int index) {
if (index == _listSavedOutsideThisWidget.length) {
return TextButton.icon(
onPressed: _onPressed(context),
icon: const Icon(Icons.upload_file),
label: const Text('Upload Data'));
}
return Container(
decoration: !isSelected
? null
: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.white,
),
child: ListTile(
selected: isSelected,
title: Text(item?.gym ?? ''),
subtitle: Text(item?.location ?? ''),
leading: (item!.avatar == "")
? const CircleAvatar(
radius: 25,
backgroundColor: Colors.white,
backgroundImage: NetworkImage(
'https://img.icons8.com/ios/100/000000/gum-.png'),
)
: CircleAvatar(
radius: 25,
backgroundImage: NetworkImage(item.avatar ?? ''),
)),
);
},
),
);
For this method to work you will have to create a List<GymModel> _listSavedOutsideThisWidget = [] variable outside the build function and populate it by changing the onFind method under DropdownSearch widget, like such:
onFind: (String? filter) async {
List<GymModel>> filteredList = await gedtData(filter);
setState(() => _listSavedOutsideThisWidget = filteredList);
// return getData(filter);
return filteredList; // if this doesn't work, try uncommenting the above line
}
Hope this helps. Feel free to ask more questions.

