Dynamic listview in flutter - flutter

I'm new to Flutter, but I'm trying to make an app with a ListView. The ListView is a list of exercises, within each exercise the number of sets can be added. The problem comes when i press the button add exercise. The above exercise with sets is just copied. I would like a new exercise tab with 0 sets. Below the code can be found.
Here is a picture of the list.
final decoratedField = InputDecoration(
filled: false,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
hintText: "null",
);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Column(
children: [
titleSection,
// ignore: unnecessary_new
new TextField(
controller: eCtrl,
onSubmitted: (text) {
litems.add(text);
eCtrl.clear();
setState(() {});
},
),
Expanded(
// ignore: unnecessary_new
child: new ListView.builder(
itemCount: litems.length,
itemBuilder: (BuildContext ctxt, int Index) {
return Card(
child: Padding(
padding: EdgeInsets.all(10),
child: ExpansionTile(
initiallyExpanded: true,
title: Text(
litems[Index],
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
subtitle: Row(
children: [
Expanded(child: Text(" ")),
//Expanded(child: Text("data")),
//Expanded(child: Text("data")),
//Expanded(child: Text("data")),
],
),
// ignore: sort_child_properties_last
children: <Widget>[
ListView.builder(
shrinkWrap: true,
itemCount: sets.length,
itemBuilder:
(BuildContext context, int Index1) {
return Dismissible(
key: UniqueKey(),
// only allows the user swipe from right to left
direction:
DismissDirection.endToStart,
// Remove this product from the list
// In production enviroment, you may want to send some request to delete it on server side
onDismissed: (_) {
setState(() {
sets.removeAt(Index1);
});
},
// ignore: sort_child_properties_last
child: Card(
elevation: 0,
child: Padding(
padding: EdgeInsets.all(1),
child: ListTile(
title: Text(
" ",
style: const TextStyle(
fontSize: 10,
fontWeight:
FontWeight.bold,
),
),
subtitle: Row(
children: [
Expanded(
child: Text(" "),
),
Expanded(
child: TextField(
decoration:
decoratedField,
),
),
Expanded(
child: TextField(
decoration:
decoratedField,
),
),
Expanded(
child: TextField(
decoration:
decoratedField,
),
),
],
),
))),
background: Container(
color: Colors.red,
margin:
const EdgeInsets.symmetric(
horizontal: 15,
),
alignment: Alignment.centerRight,
child: const Text(
"Delete",
style: TextStyle(
color: Colors.white,
),
)));
}),
Padding(
padding: EdgeInsets.all(10),
child: ElevatedButton(
onPressed: () {
sets.add('sets-test');
setState(() {});
},
child: const Text('+ Add Set')),
),
const SizedBox(height: 5),
],
leading: IconButton(
icon: const Icon(
Icons.close,
color: Colors.red,
),
onPressed: () {
litems.removeAt(Index);
setState(() {});
},
),
)));
})),
ElevatedButton(
onPressed: () {
litems.add("new");
setState(() {});
},
child: const Text('Add Exercises')),
ElevatedButton(
onPressed: () {
createUser(user1, "5");
exercise.setExerciseTotals();
//saveExercise(exercise);
final workout = Workout([exercise, exercise1], "Det gik fint",
"10", 60, "type", "name", true, 0, 0, 0);
//workout.setWorkoutTotals();
saveWorkout(workout, userID);
},
child: const Text('pop')),
bottomSection,
],
),
));
}

You are not copy the item, you logic is that add new Item with null value, change decoratedField to this:
final decoratedField = InputDecoration(
filled: false,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
),
hintText: "0",
);

Related

Flutter || Checkbox on hover doesn't give on tap cursor permission

I am working on dropdownmenu items where in the drop-down menu item there are several checkboxes but any of the checkboxes on hover don't give on tap cursor permission.
This is a very strange thing I found out as I have already used the checkbox before but this type of error I didn't receive.
I think maybe the problem is in dropdownmenu.
I have also included the video for better understanding of my problem.
my code :-
Container(
width: 160,
//margin: const EdgeInsets.only(top: 10.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5), color: Colors.white),
child: ListTileTheme(
contentPadding: EdgeInsets.all(0),
dense: true,
horizontalTitleGap: 0.0,
minLeadingWidth: 0,
child: ExpansionTile(
iconColor: primaryBackgroundLightGrey,
title: Text(
listOFSelectedItem.isEmpty
? "Project type"
: listOFSelectedItem[0],
style: t5O40),
children: <Widget>[
Container(
height: 10,
color: primaryBackgroundLightGrey,
),
ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: widget.listOFStrings.length,
itemBuilder: (BuildContext context, int index) {
return Column(
children: [
Container(
height: 10,
),
Container(
margin: const EdgeInsets.only(bottom: 8.0),
child: _ViewItem(
item: widget.listOFStrings[index],
selected: (val) {
selectedText = val;
if (listOFSelectedItem.contains(val)) {
listOFSelectedItem.remove(val);
} else {
listOFSelectedItem.add(val);
}
widget.selectedList(listOFSelectedItem);
setState(() {});
},
itemSelected: listOFSelectedItem
.contains(widget.listOFStrings[index])),
),
],
);
},
),
],
),
),
),
class _ViewItem extends StatelessWidget {
String item;
bool itemSelected;
final Function(String) selected;
_ViewItem(
{required this.item, required this.itemSelected, required this.selected});
#override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return Padding(
padding: EdgeInsets.only(
left: size.width * .015,
),
child: Row(
children: [
SizedBox(
height: 2,
width: 2,
child: Checkbox(
value: itemSelected,
onChanged: (val) {
selected(item);
},
hoverColor: Colors.transparent,
checkColor: Colors.white,
activeColor: Colors.grey),
),
SizedBox(
width: size.width * .010,
),
Text(item, style: t3O60),
],
),
);
}
}
You can adapt the example to your own code
dropdownBuilder: _customDropDownExample,
popupItemBuilder: _customPopupItemBuilderExample,
Widget _customDropDownExample(
BuildContext context, UserModel? item, String itemDesignation) {
if (item == null) {
return Container();
}
return Container(
child: (item.avatar == null)
? ListTile(
contentPadding: EdgeInsets.all(0),
leading: CircleAvatar(),
title: Text("No item selected"),
)
: ListTile(
contentPadding: EdgeInsets.all(0),
leading: CircleAvatar(
// this does not work - throws 404 error
// backgroundImage: NetworkImage(item.avatar ?? ''),
),
title: Text(item.name),
subtitle: Text(
item.createdAt.toString(),
),
),
);
After that
Widget _customPopupItemBuilderExample(
BuildContext context, UserModel item, bool isSelected) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 8),
decoration: !isSelected
? null
: BoxDecoration(
border: Border.all(color: Theme.of(context).primaryColor),
borderRadius: BorderRadius.circular(5),
color: Colors.white,
),
child: ListTile(
selected: isSelected,
title: Text(item.name),
subtitle: Text(item.createdAt.toString()),
leading: CircleAvatar(
// this does not work - throws 404 error
// backgroundImage: NetworkImage(item.avatar ?? ''),
),
),
);
I am using this package https://pub.dev/packages/dropdown_button2
Multiselect Dropdown with Checkboxes
final List<String> items = [
'Item1',
'Item2',
'Item3',
'Item4',
];
List<String> selectedItems = [];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: DropdownButtonHideUnderline(
child: DropdownButton2(
isExpanded: true,
hint: Align(
alignment: AlignmentDirectional.center,
child: Text(
'Select Items',
style: TextStyle(
fontSize: 14,
color: Theme.of(context).hintColor,
),
),
),
items: items.map((item) {
return DropdownMenuItem<String>(
value: item,
//disable default onTap to avoid closing menu when selecting an item
enabled: false,
child: StatefulBuilder(
builder: (context, menuSetState) {
final _isSelected = selectedItems.contains(item);
return InkWell(
onTap: () {
_isSelected
? selectedItems.remove(item)
: selectedItems.add(item);
//This rebuilds the StatefulWidget to update the button's text
setState(() {});
//This rebuilds the dropdownMenu Widget to update the check mark
menuSetState(() {});
},
child: Container(
height: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Row(
children: [
_isSelected
? const Icon(Icons.check_box_outlined)
: const Icon(Icons.check_box_outline_blank),
const SizedBox(width: 16),
Text(
item,
style: const TextStyle(
fontSize: 14,
),
),
],
),
),
);
},
),
);
}).toList(),
//Use last selected item as the current value so if we've limited menu height, it scroll to last item.
value: selectedItems.isEmpty ? null : selectedItems.last,
onChanged: (value) {},
buttonHeight: 40,
buttonWidth: 140,
itemHeight: 40,
itemPadding: EdgeInsets.zero,
selectedItemBuilder: (context) {
return items.map(
(item) {
return Container(
alignment: AlignmentDirectional.center,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
selectedItems.join(', '),
style: const TextStyle(
fontSize: 14,
overflow: TextOverflow.ellipsis,
),
maxLines: 1,
),
);
},
).toList();
},
),
),
),
);
}

Error on my UI using SingleChildScrollView when i try to run my firebase?

this is my first time using community to ask about my project. First thing first, english isn't my first language and I'm a very beginner in flutter world. I'm trying to build my first mobile application using flutter and now I'm trying to connect my project to firebase (I looked at youtube tutorial). I don't know if the firebase already connect because when I'm trying to run the application and go to registration page, there this error message.
And here is my code:
import 'package:dfu_check_application/common/auth_controller.dart';
import 'package:flutter/material.dart';
import 'package:dfu_check_application/common/theme_helper.dart';
import 'package:dfu_check_application/pages/widgets/header_widget.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:hexcolor/hexcolor.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'profile_page.dart';
class RegistrationPage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _RegistrationPageState();
}
}
class _RegistrationPageState extends State<RegistrationPage> {
final _formKey = GlobalKey<FormState>();
bool checkedValue = false;
bool checkboxValue = false;
#override
Widget build(BuildContext context) {
var nameController = TextEditingController();
var emailController = TextEditingController();
var passwordController = TextEditingController();
return Scaffold(
backgroundColor: Colors.white,
body: SingleChildScrollView(
child: Stack(children: [
Container(
height: 150,
child: HeaderWidget(150, false, Icons.person_add_alt_1_rounded),
),
Container(
margin: EdgeInsets.fromLTRB(25, 50, 25, 10),
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
alignment: Alignment.center,
child: Column(
children: [
Form(
key: _formKey,
child: Column(
children: [
GestureDetector(
child: Stack(
children: [
Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
border:
Border.all(width: 5, color: Colors.white),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 20,
offset: const Offset(5, 5),
),
],
),
child: Icon(
Icons.person,
color: Colors.grey.shade300,
size: 80.0,
),
),
Container(
padding: EdgeInsets.fromLTRB(80, 80, 0, 0),
child: Icon(
Icons.add_circle,
color: Colors.grey.shade700,
size: 25.0,
),
),
],
),
),
SizedBox(
height: 30,
),
Container(
child: TextFormField(
controller: nameController,
decoration: ThemeHelper().textInputDecoration(
'Full Name', 'Enter your full name'),
),
decoration: ThemeHelper().inputBoxDecorationShaddow(),
),
SizedBox(
height: 30,
),
SizedBox(height: 20.0),
Container(
child: TextFormField(
controller: emailController,
decoration: ThemeHelper().textInputDecoration(
"E-mail address", "Enter your email"),
keyboardType: TextInputType.emailAddress,
validator: (val) {
// ignore: prefer_is_not_empty
if (!(val!.isEmpty) &&
!RegExp(r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+#[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?)*$")
.hasMatch(val)) {
return "Enter a valid email address";
}
return null;
},
),
decoration: ThemeHelper().inputBoxDecorationShaddow(),
),
SizedBox(height: 20.0),
Container(
child: TextFormField(
obscureText: true,
controller: passwordController,
decoration: ThemeHelper().textInputDecoration(
"Password*", "Enter your password"),
validator: (val) {
if (val!.isEmpty) {
return "Please enter your password";
}
return null;
},
),
decoration: ThemeHelper().inputBoxDecorationShaddow(),
),
SizedBox(height: 15.0),
FormField<bool>(
builder: (state) {
return Column(
children: <Widget>[
Row(
children: <Widget>[
Checkbox(
value: checkboxValue,
onChanged: (value) {
setState(() {
checkboxValue = value!;
state.didChange(value);
});
}),
Text(
"I accept all terms and conditions.",
style: TextStyle(color: Colors.grey),
),
],
),
Container(
alignment: Alignment.centerLeft,
child: Text(
state.errorText ?? '',
textAlign: TextAlign.left,
style: TextStyle(
color: Theme.of(context).errorColor,
fontSize: 12,
),
),
)
],
);
},
validator: (value) {
if (!checkboxValue) {
return 'You need to accept terms and conditions';
} else {
return null;
}
},
),
SizedBox(height: 20.0),
GestureDetector(
onTap: () {
AuthController.instance.register(
nameController.text.trim(),
emailController.text.trim(),
passwordController.text.trim());
},
),
Container(
decoration: ThemeHelper().buttonBoxDecoration(context),
child: ElevatedButton(
style: ThemeHelper().buttonStyle(),
child: Padding(
padding: const EdgeInsets.fromLTRB(40, 10, 40, 10),
child: Text(
"Register".toUpperCase(),
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
onPressed: () {
if (_formKey.currentState!.validate()) {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) => ProfilePage()),
(Route<dynamic> route) => false);
}
},
),
),
SizedBox(height: 30.0),
Text(
"Or create account using social media",
style: TextStyle(color: Colors.grey),
),
SizedBox(height: 25.0),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
child: FaIcon(
FontAwesomeIcons.google,
size: 35,
color: HexColor("#EC2D2F"),
),
onTap: () {
setState(() {
showDialog(
context: context,
builder: (BuildContext context) {
return ThemeHelper().alartDialog(
"Google Account",
"You tap on Google icon.",
context);
},
);
});
},
),
],
),
],
),
),
],
),
),
]),
),
);
}
}
If you guys see more error on my code, please tell me because I'm very clueless about this. Thank you in advance!
The issue occurs from Stack the one inside
Column(
children: [
Form(
key: _formKey,
child: Column(
children: [
GestureDetector(
child: Stack( // this one
Can be fixed by providing hight
GestureDetector(
child: SizedBox(
height: MediaQuery.of(context).size.height, //this based on your need
child: Stack(
I think you can re struct the widget and don't need to use multi-Stack.
More about /ui/layout and Unbounded height / width

Not able to get element index in a listview - Flutter

i'm trying to make operations on clicked elements in a listView in flutter. An alertDialog should appear once I click an element so I can update its value. My backend works perfectly using the put http method. The problem is that i'm able to read the input value in console but not able to read the index of the clicked element.
As it's mentionned above, i'm able to read the input value which means that my api works correctly, but not able to retrieve the clicked element's index in the listView.
Console output:
I/flutter ( 4120): ============================== null
I/flutter ( 4120): 33
here is my update function:
handleMeasurement(String iv_id, String value) async {
final response = await http.put(
Uri.parse('${baseUrl}/api/v1/measurements/update/' + iv_id),
body: <String, String>{
"input_value": value
});
}
and here is my ui:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(
'Traitement des mesures',
style: TextStyle(color: Colors.black),
),
centerTitle: true,
),
body: Visibility(
visible: isLoaded,
replacement: Center(child: CircularProgressIndicator()),
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
padding: EdgeInsets.all(15),
itemCount: mesures?.length,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () => showDialog<String>(
context: context,
builder: (BuildContext context) => AlertDialog(
title: const Text('Mesure'),
content: TextField(
controller: _textFieldController,
decoration:
InputDecoration(hintText: "Entrez la valeur"),
),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context, 'Cancel'),
child: const Text('Cancel'),
),
TextButton(
onPressed: () => {
print(
"============================== ${mesures![index].measurement_id}"),
print(_textFieldController.text),
handleMeasurement(
"${mesures![index].measurement_id}",
_textFieldController.text),
Navigator.pop(context, 'OK')
},
child: const Text('OK'),
),
],
),
),
child: Container(
margin: EdgeInsets.only(bottom: 15),
child: Row(
children: [
SizedBox(
width: 70,
child: AspectRatio(
aspectRatio: 0.88,
child: Container(
decoration: BoxDecoration(
color: Color(0xFFF5F6F9),
borderRadius: BorderRadius.circular(15),
),
child: Image.asset(
'assets/note2.png',
),
),
),
),
SizedBox(width: 20),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Paramètre: ${mesures![index].param_name}",
style: TextStyle(
color: Colors.black, fontSize: 16),
maxLines: 2,
),
SizedBox(height: 10),
Text.rich(
TextSpan(
text:
"Description: ${mesures![index].description}",
style: TextStyle(
fontWeight: FontWeight.w600,
color: kPrimaryColor),
),
),
],
),
],
),
),
);
},
),
)
],
),
),
);
}
Can anyone help me out with it? thanks in advance!

How do I stop contents of my ListView extending beyond its boundaries when scrolling in Flutter?

I have a strange problem with a ListView in my Flutter app.
I have a ListView sitting within a SizedBox of 220 pixels height. When the list items exceed the available height, then they bleed over into surrounding screen elements.
Weirdly there is ONE property of the ListTile's that DO clip and that's the title! but everything else, the color and shape etc... bleeds into the rest of the screen so I get a load of blue boxes extending beyond my container.
Can anyone advise how I can have the ENTIRE ListTile clip when it meets the edge of its container?
Please reference the screenshot to see what I mean and i'll paste my code below the image
Here's my build method...
#override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
return SafeArea(
child: Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
leading: const CloseButton(),
actions: [
ElevatedButton.icon(
label: const Text('SAVE'),
icon: const Icon(Icons.done),
onPressed: () async {
Navigator.pop(context);
widget.resolution?.wasSaved = true;
setState(() {
resolution.title = titleController.text;
});
widget.onSaved(resolution);
},
style: ElevatedButton.styleFrom(
primary: Colors.transparent,
elevation: 0,
),
),
],
),
body: Container(
// height: size.height,
padding: const EdgeInsets.all(12),
child: Column(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('RESOLUTION', style: kInputFieldHeader),
const SizedBox(height: 4),
Card(
elevation: 2,
child: TextFormField(
style: kInputFieldText,
controller: titleController,
decoration: InputDecoration(
border: OutlineInputBorder(),
suffixIcon: titleController.text.isEmpty
? Container(
width: 0,
)
: IconButton(
onPressed: () => titleController.clear(),
icon: Icon(Icons.close))),
onFieldSubmitted: (fieldText) {
setState(() {
resolution.title = fieldText;
});
;
},
validator: (value) => value != null && value.isEmpty
? 'Please enter something'
: null,
),
),
DatePickers(
resolution: resolution,
startDateCallback: (startDate) {
setState(() {
resolution.startDate = startDate;
});
},
endDateCallback: (endDate) {
setState(() {
resolution.endDate = endDate;
});
},
),
CustomColorPicker(
resolution: resolution,
colorCallback: (color) =>
setState(() => resolution.color = color),
),
CustomProgressIndicator(
resolution: resolution, isCommitment: false),
],
),
Expanded(
child: Stack(
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('COMMITMENTS', style: kInputFieldHeader),
const SizedBox(height: 10),
Expanded(
child: SizedBox(
height: 220,
child: Container(
child: commitments.isNotEmpty
? _buildCommitmentsList()
: _buildEmptyCommitments(),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
border:
Border.all(width: 1, color: Colors.grey),
),
),
),
),
],
),
Positioned(
bottom: 10,
right: 10,
child: FloatingActionButton(
heroTag: const Text('newCommitment'),
child: const Icon(Icons.add, size: 30),
onPressed: () => _commitmentScreenNew())),
],
),
),
TextButton(
onPressed: () {
Navigator.pop(context);
widget.onDeleted(resolution);
},
child: const Text(
'DELETE RESOLUTION',
)),
],
),
),
),
);
}
And here's the listView builder method...
_buildCommitmentsList() {
return ListView.builder(
itemCount: commitments.length,
physics: const BouncingScrollPhysics(),
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
child: ListTile(
title: Text(commitments[index].description),
tileColor: resolution.color,
onTap: () => _commitmentScreenEdit(commitments[index]),
onLongPress: () => _removeCommitment(commitments[index]),
),
);
},
);
}
Any help would be greatly appreciated :)
Just for the record, I eventually resolved this by replacing the ListTiles with coloured containers.

Searchbar didn't worked properly in the draggablescrollablesheet (Flutter)

I'm a Flutter newbie. I had a trouble with my own searchbar in the draggable bottom sheet. I created a draggable bottom sheet to search for information when clicking to the search field from the main screen. I added a searchbar and a listview in the sheet but the searchbar did not work properly. It could not instantly filter out the data, it just showed the results when closing the keyboard. Anyone helps me please.
class AddPersonalInfo extends StatefulWidget {
final String mail, password;
const AddPersonalInfo({Key? key, required this.mail, required this.password})
: super(key: key);
#override
_AddPersonalInfoState createState() => _AddPersonalInfoState();
}
class _AddPersonalInfoState extends State<AddPersonalInfo> {
TextEditingController _search = TextEditingController();
List<City> cites = [
City(id: 1, code: "HN", name: "Ha Noi"),
City(id: 2, code: "HCM", name: "Ho CHi Minh"),
City(id: 3, code: "DN", name: "Da Nang"),
City(id: 4, code: "HP", name: "Hai Phong"),
City(id: 5, code: "CT", name: "Can Tho"),
City(id: 6, code: "DNN", name: "Dong Nai"),
City(id: 7, code: "KH", name: "Khanh Hoa"),
City(id: 8, code: "PY", name: "Phu Yen"),
City(id: 9, code: "NT", name: "Nha Trang"),
City(id: 10, code: "VL", name: "Vinh Long"),
City(id: 11, code: "HD", name: "Hai Duong"),
City(id: 12, code: "BD", name: "Binh Duong")
];
City? selected;
List<City> foundCity = [];
#override
void initState() {
super.initState();
setState(() {
foundCity = cites;
});
}
#override
Widget build(BuildContext context) {
Size screenSize = MediaQuery.of(context).size;
Orientation orientation = MediaQuery.of(context).orientation;
return GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: LayoutBuilder(builder: (context, snapshot) {
if (snapshot.maxWidth <= screenSize.width &&
orientation == Orientation.portrait) {
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Container(
padding: EdgeInsets.fromLTRB(30 * screenScale(context), 0,
30 * screenScale(context), 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Stack(
children: [
Container(
alignment: Alignment.topCenter,
padding: EdgeInsets.only(
bottom: 20 * screenScale(context)),
child: introText("Create account", context),
),
backBtn(context),
],
),
mainText(
"Let's create an account to grab all latest gadgets and enjoy the best experiences.",
context),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [_fnameField(), _lnameField()],
),
_phoneField(),
GestureDetector(
onTap: () => showModalBottomSheet(
backgroundColor: Colors.transparent,
isScrollControlled: true,
context: context,
builder: (context) => buildSheet(),
),
child: Container(
height: 50,
margin: EdgeInsets.only(top: 15),
padding: EdgeInsets.only(left: 10, right: 7),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(7),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
selected == null
? Text("Select city",
style: TextStyle(
fontSize: 16,
color: Colors.grey.shade700))
: Text("${selected!.name}",
style: TextStyle(
fontSize: 16, color: Colors.black)),
Icon(Ionicons.chevron_down_outline, size: 24)
],
),
),
)
],
),
),
);
} else {
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Container(
padding: EdgeInsets.fromLTRB(30 * screenScale(context), 0,
30 * screenScale(context), 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [],
),
),
);
}
}),
),
),
);
}
Widget buildSheet() {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.of(context).pop();
},
child: DraggableScrollableSheet(
initialChildSize: 0.9,
builder: (_, controller) => Container(
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
child: Column(
children: [
Divider(
thickness: 4,
color: Colors.grey.shade300,
endIndent: 170,
indent: 170,
),
Padding(
padding: EdgeInsets.only(bottom: 15, top: 5),
child: Text("Select city",
style: TextStyle(
fontSize: 18,
color: Colors.black,
fontWeight: FontWeight.bold)),
),
Padding(
padding: EdgeInsets.only(bottom: 10),
child: TextFormField(
controller: _search,
keyboardType: TextInputType.name,
style: TextStyle(fontSize: 16 * fontScale(context)),
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(7 * screenScale(context))),
contentPadding:
EdgeInsets.only(top: 10 * screenScale(context)),
hintText: 'Search',
prefixIcon: Icon(Ionicons.search_outline),
),
onChanged: (value) {
setState(() {
foundCity = cites
.where(
(city) => city.name.toLowerCase().contains(value))
.toList();
});
},
),
),
Expanded(
child: foundCity.length > 0
? ListView.builder(
itemCount: foundCity.length,
itemBuilder: (context, index) {
final city = foundCity[index];
return ListTile(
title: Text(city.name),
onTap: () {
Navigator.of(context).pop();
setState(() {
selected = city;
});
},
);
},
)
: Padding(
padding: EdgeInsets.only(top: 50),
child: Text(
"No data.",
style: TextStyle(fontSize: 16),
),
),
),
],
),
),
),
);
}
}
Ok I checked you code, and it seems you missed a small issue, when you're creating a showModalBottomSheet, it's no longer part of your stateful widget
I've adjusted the code so that it works now:
Widget buildSheet(BuildContext context) {
return StatefulBuilder(builder: (BuildContext context, setState) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.of(context).pop();
},
child: DraggableScrollableSheet(
initialChildSize: 0.9,
builder: (_, controller) => Container(
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
child: Column(
children: [
Divider(
thickness: 4,
color: Colors.grey.shade300,
endIndent: 170,
indent: 170,
),
Padding(
padding: EdgeInsets.only(bottom: 15, top: 5),
child: Text("Select city",
style: TextStyle(
fontSize: 18,
color: Colors.black,
fontWeight: FontWeight.bold)),
),
Padding(
padding: EdgeInsets.only(bottom: 10),
child: TextFormField(
controller: _search,
keyboardType: TextInputType.name,
style: TextStyle(fontSize: 16),
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(7)),
contentPadding: EdgeInsets.only(top: 10),
hintText: 'Search',
prefixIcon: Icon(Icons.access_alarm),
),
onChanged: (value) {
setState(() {
foundCity = cites
.where((city) =>
city.name!.toLowerCase().contains(value))
.toList();
});
},
),
),
Expanded(
child: foundCity.isNotEmpty
? ListView.builder(
itemCount: foundCity.length,
itemBuilder: (context, index) {
final city = foundCity[index];
return ListTile(
title: Text(city.name!),
onTap: () {
Navigator.of(context).pop();
setState(() {
selected = city;
});
},
);
},
)
: Padding(
padding: EdgeInsets.only(top: 50),
child: Text(
"No data.",
style: TextStyle(fontSize: 16),
),
),
),
],
),
),
),
);
});
}