Searchbar didn't worked properly in the draggablescrollablesheet (Flutter) - 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),
),
),
),
],
),
),
),
);
});
}

Related

Flutter : Get Value of Selected Container

I am trying to get the Text value of the selected container in a GridView. I am able to print the selected index. But I need to get the text value of the selected container so that I can save it in sharedPreferences and later get it and store it on the server.
Please assist. Your help will be gladly appreciated.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class QuickSurveyScreen extends StatefulWidget {
const QuickSurveyScreen({super.key});
#override
State<QuickSurveyScreen> createState() => _QuickSurveyScreenState();
}
class _QuickSurveyScreenState extends State<QuickSurveyScreen> {
int selectedIndex = -1;
List<String> gasUsage = [
"Heater",
"Stove",
"Geyser",
"Fireplace",
];
#override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.only(top: 120.0, right: 30, left: 30),
child: Column(
children: const [
Text(
"What do you use \nLP Gas for?",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold),
),
Padding(
padding: EdgeInsets.symmetric(
vertical: 16.0,
horizontal: 20,
),
child: Text(
"Please choose one or more options from below",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18,
),
),
),
],
),
))
];
},
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
children: [
Expanded(
child: GridView.builder(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 1.0,
crossAxisSpacing: 20.0,
mainAxisSpacing: 20.0,
),
physics: const NeverScrollableScrollPhysics(),
itemCount: gasUsage.length,
itemBuilder: (BuildContext context, int index) {
return gasUsageContainer("", gasUsage[index], index);
}),
),
ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
minimumSize: const Size(double.infinity, 65.0),
backgroundColor: const Color(0xFFF0A202),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(26.0),
),
textStyle: const TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
child: const Text('Continue'),
),
],
),
),
),
),
);
}
gasUsageContainer(String image, String name, int index) {
return GestureDetector(
onTap: () {
setState(() {
if (selectedIndex == index) {
selectedIndex = -1;
} else {
selectedIndex = index;
}
if (kDebugMode) {
print(selectedIndex);
}
});
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
padding: const EdgeInsets.all(10.0),
decoration: BoxDecoration(
color: selectedIndex == index
? Colors.amber.shade50
: Colors.grey.shade200,
border: Border.all(
color: selectedIndex == index
? Colors.amber
: Colors.blue.withOpacity(0),
width: 2.0,
),
borderRadius: BorderRadius.circular(22.0),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
name,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: selectedIndex == index
? Colors.amber.shade800
: Colors.black,
),
)
]),
),
);
}
}
You can get it from List with index. Checkout the change I did for onTap in gasUsageContainer
onTap: () {
setState(() {
String? selected;
if (selectedIndex == index) {
selectedIndex = -1;
selected = null;
} else {
selectedIndex = index;
selected = gasUsage[index];//Here you get the value
}
if (kDebugMode) {
print('selectedIndex:$selectedIndex, selected: $selected');
}
});
}
Edited
class _QuickSurveyScreenState extends State<QuickSurveyScreen> {
final selectedItems = <String>[];
...
gasUsageContainer(String image, String name, int index) {
String item = gasUsage[index];
return GestureDetector(
onTap: () {
setState(() {
if (selectedItems.contains(item)) {
selectedItems.remove(item);
} else {
selectedItems.add(item);
}
if (kDebugMode) {
print('selectedItems: $selectedItems');
}
});
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
padding: const EdgeInsets.all(10.0),
decoration: BoxDecoration(
color: selectedItems.contains(item)
? Colors.amber.shade50
: Colors.grey.shade200,
border: Border.all(
color: selectedItems.contains(item)
? Colors.amber
: Colors.blue.withOpacity(0),
width: 2.0,
),
borderRadius: BorderRadius.circular(22.0),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
name,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: selectedItems.contains(item)
? Colors.amber.shade800
: Colors.black,
),
)
]),
),
);
}
}

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

ListView.builder returns Null check operator used on a null value

I'm developing a job search app that scrapes data from Indeed using Python which is being sent back to my Flutter UI as JSON data. The JSON data is being received successfully, however, Im getting an error of Null check operator used on a null value. The error appears to be stemming from the _jobSearch widget.
The relevant error-causing widget was ListView lib/ui/home_page.dart:256
Exception caught by scheduler library
Null check operator used on a null value
Here is the code:
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:flutter_job_portal/theme/colors.dart';
import 'package:flutter_job_portal/theme/images.dart';
import 'package:flutter_job_portal/ui/bottom_menu_bar.dart';
import 'package:flutter_job_portal/ui/job_detail_page.dart';
String job = ""; //user's response will be assigned to this variable
String final_response = "";
final _formkey = GlobalKey<FormState>(); //key created to interact with the form
//function to validate and save user form
Future<void> _savingData() async {
final validation = _formkey.currentState.validate();
if (!validation) {
return;
}
_formkey.currentState.save();
}
Future<List<Job>> _getJobs() async {
final url = 'http://127.0.0.1:5000/job';
final response1 = await http.post(Uri.parse(url), body: json.encode({'job': job}));
final response2 = await http.get(Uri.parse(url));
final decoded = json.decode(response2.body);
List<Job> jobs = [];
for (var i in decoded) {
Job job = Job(i['Title'], i['Company'], i['Location'], i['Salary']);
jobs.add(job);
}
return jobs;
}
class Job {
final String title;
final String company;
final String location;
final String salary;
Job(this.title, this.company, this.location, this.salary);
}
class HomePage extends StatelessWidget {
const HomePage({Key key}) : super(key: key);
Widget _appBar(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 10),
child: Row(
children: [
CircleAvatar(
backgroundImage: AssetImage(Images.user1),
),
Spacer(),
IconButton(
icon: Icon(Icons.notifications_none_rounded),
onPressed: () {},
)
],
),
);
}
Widget _header(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(vertical: 12),
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Hello, Alex!",
style: TextStyle(
fontSize: 15,
color: KColors.subtitle,
fontWeight: FontWeight.w500,
)),
SizedBox(
height: 6,
),
Text("Swipe to find your future",
style: TextStyle(
fontSize: 20,
color: KColors.title,
fontWeight: FontWeight.bold)),
SizedBox(
height: 10,
),
Row(
children: [
Expanded(
child: Container(
height: 45,
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
color: KColors.lightGrey,
borderRadius: BorderRadius.circular(10)),
child: Form(
key: _formkey,
child: TextFormField(
decoration: InputDecoration(
hintText: 'Search job title or keywords',
),
onSaved: (value) {
job =
value; //getting data from the user form and assigning it to job
},
),
),
),
),
SizedBox(
width: 16,
),
Container(
decoration: BoxDecoration(
color: KColors.primary,
borderRadius: BorderRadius.circular(10),
),
height: 40,
child: IconButton(
color: KColors.primary,
icon: Icon(Icons.search, color: Colors.white),
onPressed: () async {
_savingData();
_getJobs();
},
),
)
],
)
],
),
);
}
Widget _recommendedSection(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 10),
margin: EdgeInsets.symmetric(vertical: 12),
height: 200,
width: MediaQuery.of(context).size.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Recommended",
style: TextStyle(fontWeight: FontWeight.bold, color: KColors.title),
),
SizedBox(height: 10),
Expanded(
child: ListView(
scrollDirection: Axis.horizontal,
children: [
_recommendedJob(context,
company: "Google",
img: Images.google,
title: "UX Designer",
sub: "\$45,000 Remote",
isActive: true),
_recommendedJob(context,
company: "DropBox",
img: Images.dropbox,
title: "Research Assist",
sub: "\$45,000 Remote",
isActive: false)
],
),
),
],
),
);
}
Widget _recommendedJob(
BuildContext context, {
String img,
String company,
String title,
String sub,
bool isActive = false,
}) {
return Padding(
padding: const EdgeInsets.only(right: 10),
child: GestureDetector(
onTap: () {
Navigator.push(context, JobDetailPage.getJobDetail());
},
child: AspectRatio(
aspectRatio: 1.3,
child: Container(
decoration: BoxDecoration(
color: isActive ? KColors.primary : Colors.white,
borderRadius: BorderRadius.circular(7),
),
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 40,
width: 40,
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
color: isActive ? Colors.white : KColors.lightGrey,
borderRadius: BorderRadius.circular(7),
),
child: Image.asset(img),
),
SizedBox(height: 16),
Text(
company,
style: TextStyle(
fontSize: 12,
color: isActive ? Colors.white38 : KColors.subtitle,
),
),
SizedBox(height: 6),
Text(
title,
style: TextStyle(
fontSize: 14,
color: isActive ? Colors.white : KColors.title,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 6),
Text(
sub,
style: TextStyle(
fontSize: 12,
color: isActive ? Colors.white38 : KColors.subtitle,
),
),
],
),
),
),
),
);
}
Widget _jobSearch(BuildContext context) {
return new Container(
child: FutureBuilder(
future: _getJobs(),
builder: (context, snapshot) {
if (snapshot.data == null) {
return Container(
child: Center(
child: Text('Loading...'),
));
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(snapshot.data[index].location),
);
},
);
}
},
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: KColors.background,
bottomNavigationBar: BottomMenuBar(),
body: SafeArea(
child: Container(
width: MediaQuery.of(context).size.width,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_appBar(context),
_header(context),
_recommendedSection(context),
_jobSearch(context)
],
),
),
),
),
);
}
}

Tab Bar in Flutter

I want to implement Tab Bar in my application having length 2 named "Need Help" and "Help Requests". In "Need Help" tab, I want my first container (i.e. Upload data to Firestore Database) and in "Help Requests" tab, I want my second container (i.e. Retrieve data from Firestore Database). I am new to flutter and will be very much grateful to you if you can help me.
Source code:
import 'package:chat_app/group_chats/group_info.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import '../constants.dart';
import '../global_data.dart';
class FinancialRoom extends StatelessWidget {
final String groupChatId, groupName;
FinancialRoom({required this.groupName, required this.groupChatId, Key? key})
: super(key: key);
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final FirebaseAuth _auth = FirebaseAuth.instance;
final _formKey = GlobalKey<FormState>();
TextEditingController amountValue = TextEditingController();
void onSend() async {
Map<String, dynamic> data = {
"amount": amountValue.text,
"sendBy": _auth.currentUser!.displayName,
"type": "text",
"time": FieldValue.serverTimestamp(),
};
amountValue.clear();
await _firestore
.collection('groups')
.doc(groupChatId)
.collection('chats')
.add(data);
}
#override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
return Scaffold(
appBar: AppBar(
title: Text(groupName),
actions: [
IconButton(
onPressed: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => GroupInfo(
groupName: groupName,
groupId: groupChatId,
),
),
),
icon: Icon(Icons.more_vert)),
],
),
body: SafeArea(
child: ListView(padding: EdgeInsets.all(20.0), children: [
Container(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(
height: 10.0,
),
TextFormField(
controller: amountValue,
decoration: InputDecoration(
hintText: 'Enter the amount you want',
labelText: 'Enter the amount you want',
prefixIcon: Icon(Icons.account_balance_wallet_outlined),
enabledBorder: kEnabledBorder,
focusedBorder: kFocusedBorder,
errorBorder: kErrorBorder,
focusedErrorBorder: kErrorBorder,
),
onTap: () {
},
// The validator receives the text that the user has entered.
validator: (value) {
if (value!.isEmpty) {
return 'Please enter the amount you want';
}
return null;
},
),
SizedBox(
height: kInputSpacing,
),
SizedBox(
width: double.infinity,
child: FlatButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0)),
color: Colors.blue,
textColor: Colors.white,
padding: EdgeInsets.only(top: 16.0, bottom: 16.0),
onPressed: onSend,
child: Text(
'SEND',
style: kButtonTextStyle,
),
),
),
],
),
),
Container(
height: size.height / 1.27,
width: size.width,
child: StreamBuilder<QuerySnapshot>(
stream: _firestore
.collection('groups')
.doc(groupChatId)
.collection('chats')
.orderBy('time')
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
Map<String, dynamic> data =
snapshot.data!.docs[index].data()
as Map<String, dynamic>;
return messageTile(size, data);
},
);
} else {
return Container();
}
},
),
),
]),
),
);
}
Widget messageTile(Size size, Map<String, dynamic> data) {
return Builder(builder: (_) {
if (data['type'] == "text") {
return Container(
width: size.width,
alignment: data['sendBy'] == _auth.currentUser!.displayName
? Alignment.centerRight
: Alignment.centerLeft,
child: Container(
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 14),
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.blue,
),
child: Column(
children: [
Text(
data['sendBy'],
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Colors.white,
),
),
SizedBox(
height: size.height / 200,
),
Text(
data['amount'],
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.white,
),
),
],
)),
);
} else if (data['type'] == "img") {
return Container(
width: size.width,
alignment: data['sendBy'] == _auth.currentUser!.displayName
? Alignment.centerRight
: Alignment.centerLeft,
child: Container(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 14),
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 8),
height: size.height / 2,
child: Image.network(
data['amount'],
),
),
);
} else if (data['type'] == "notify") {
return Container(
width: size.width,
alignment: Alignment.center,
child: Container(
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8),
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.black38,
),
child: Text(
data['message'],
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
);
} else {
return SizedBox();
}
});
}
}
It's very straightforward to implement a simple TabBar in your app. All you need is a TabController and two widgets called TabBar and TabBarView. Here is a simple example:
DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(tabs: [
Tab(text: 'Tab 1'),
Tab(text: 'Tab 2'),
]),
),
body: TabBarView(children: [
// Tab 1
Container(color: Colors.red),
// Tab 2
Container(color: Colors.blue),
]),
),
);
Now all you need to do is to replace children inside TabBarView with whatever you want to display.