Flutter - How to add scrollview to column with listview in flutter - flutter

I have a container with a column that have three containers and one listview wrapped with expanded which works perfectly but am trying to add a scrollview to the whole container so that on the three scroll with the listview, please how can I achieve this? Below is what my code looks like.
List<Content> content = [];
_fetchComments() async {
setState(() {
isLoading = true;
_isDealButtonRefresh = true;
});
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
print('connected');
String baseURL;
debugPrint("my select:$_mySelection");
if (_mySelection == null && _myFeatureSelection == null) {
baseURL = "myjson link";
} else if (_myFeatureSelection != null) {
baseURL =
"my json link" +
_myFeatureSelection;
debugPrint("feature enter");
_mySelection = null;
} else if (_mySelection != null && _myFeatureSelection == null) {
baseURL = "my json link" +
_mySelection;
}
print("our url:$baseURL");
final response = await http.get(baseURL);
if (response.statusCode == 200) {
print(response.body);
content = (json.decode(response.body) as List)
.map((data) => new Content.fromJson(data))
.toList();
setState(() {
print(response.body);
isLoading = false;
_isDealButtonRefresh = false;
});
} else {
print(response.body);
throw Exception('Failed to load post');
}
}
} on SocketException catch (_) {
print('not connected');
setState(() => isLoading = false);
Navigator.pushReplacement(
context,
new MaterialPageRoute(
builder: (BuildContext context) => NoInternet()));
}
}
initState() {
super.initState();
_fetchComments();
}
body: Container(
child: Column(children: <Widget>[
Container(),
Container(),
Container(),
Expanded(child: ListView.separated(
separatorBuilder:
(context, index) => Divider(
color: Colors.grey,
),
itemCount: content == null
? 0
: _searchResult.length,
itemBuilder:
(context, position) {
final current =
_searchResult[position];
double myrate = double.parse(
_searchResult[position]
.ratings ==
null
? "0"
: _searchResult[position]
.ratings);
debugPrint("rato:$myrate");
return FutureBuilder<String>(
future: getDistance(
current.lat,
current.lng)
.then((value) =>
value.toString()),
builder:
(context, snapshot) {
return Container(
child:
GestureDetector(
onTap: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext ctx) => Maps(_searchResult[position])));
},
child:
Column(
children: <
Widget>[
Row(
children: <
Widget>[
Expanded(
child:Container(
height:150,
width: MediaQuery.of(context).size.width,
child: SizedBox(
child: FadeInImage(image: NetworkImage(_searchResult[position].thumbnail_name), placeholder: AssetImage("assets/640x360.png"),
fit: BoxFit.cover,),
),
)),
],
),
Container(
padding:
const EdgeInsets.all(5.0),
child:
Row(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
Container(
padding: const EdgeInsets.only(bottom: 1.0),
child: Text(
_searchResult[position].title,
style: TextStyle(fontFamily: 'Montserrat', fontSize: 13, fontWeight: FontWeight.bold),
),
),
Container(
padding: const EdgeInsets.only(bottom: 1.0),
child: Text(
_searchResult[position].address,
maxLines: 2,
style: TextStyle(fontFamily: 'Montserrat', fontSize: 10, color: Colors.black54),
),
),
Container(
padding: const EdgeInsets.only(bottom: 1.0),
child: _status != PermissionStatus.denied
? snapshot.hasData
? Text(
snapshot.data + " " + "km",
maxLines: 1,
style: TextStyle(fontFamily: 'Montserrat', fontSize: 10, fontWeight: FontWeight.bold, color: colorBlue),
)
: SizedBox(
child: CircularProgressIndicator(
valueColor: new AlwaysStoppedAnimation<Color>(
colorBlue,
),
strokeWidth: 1,
),
height: 5.0,
width: 5.0,
)
: Icon(
Icons.do_not_disturb,
color: Colors.red,
size: 15,
), ),
SizedBox(
height: 2,
),
Container(
child: Text(
_searchResult[position].price + " " + "USD",
style: TextStyle(
color: colorPink,
fontWeight: FontWeight.bold,
fontSize: 12,
fontFamily: 'Montserrat',
),
),
)
],
crossAxisAlignment: CrossAxisAlignment.start,
),
flex: 9,
),
Column(
children: <Widget>[
Container(
padding: const EdgeInsets.only(bottom: 0),
child: SmoothStarRating(
allowHalfRating: false,
onRatingChanged: (v) {
setState(() {});
},
starCount: 5,
rating: myrate,
size: 12.0,
filledIconData: Icons.star,
halfFilledIconData: Icons.star_half,
color: Colors.orange,
borderColor: Colors.orange,
spacing: 0.0)),
Text(
"(" + myrate.toStringAsFixed(1) + ")",
style: TextStyle(color: Colors.black, fontFamily: 'Montserrat', fontSize: 10, fontWeight: FontWeight.bold, fontStyle: FontStyle.normal),
),
],
)
],
),
)
],
)));
});
}))
])
)
In the above code the listview fetch it data from json rest API.

You could add the 3 inner containers as children of the listview.
Something like this:
Widget getListView(yourListWithData) {
List<Widget> listViewChildren = [
Container(),
Container(),
Container(),
];
listViewChildren.addAll(
yourListWithData
.map(
(e) => Text(e), //text widget as an example, use your own widget
)
.toList(),
);
return ListView(
children: listViewChildren,
);
}
And then you can get rid of the Column and make the listview the only child of the parent container:
Container(
child: getListView(yourListWithData),
);

To solve that:
Add SingleChildScrollView Widget at the beginning with physics: ClampingScrollPhysics() propertie .
Add shrinkWrap: true propertie to your Listview .
SingleChildScrollView(
scrollDirection: Axis.vertical,
physics: ClampingScrollPhysics(),
child: Container(
child: Column( crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(),
Container(),
Container(),
Expanded(child: Listview.builder(shrinkWrap: true,))
])
)
I hope to help you

So finally after many months of research, I was able to resolve this by giving the height of each container. Since I want the height of the listview to cover most of the space in the activity I didn't set the height for the Container with the ListView. First I changed the Expanded() above to Container(), set ListView shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), . Find below my updated code:
body: Container(
child: Column(children: <Widget>[
Container(height: MediaQuery.of(context).size.height * 0.16,
),
Container(height: MediaQuery.of(context).size.height * 0.16,
),
Container(height: MediaQuery.of(context).size.height * 0.16,
),
Container(child: ListView.separated(shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
separatorBuilder:
(context, index) => Divider(
color: Colors.grey,
),
itemCount: content == null
? 0
: _searchResult.length,
itemBuilder:
(context, position) {
final current =
_searchResult[position];
double myrate = double.parse(
_searchResult[position]
.ratings ==
null
? "0"
: _searchResult[position]
.ratings);
debugPrint("rato:$myrate");
return FutureBuilder<String>(
future: getDistance(
current.lat,
current.lng)
.then((value) =>
value.toString()),
builder:
(context, snapshot) {
return Container(
child:
GestureDetector(
onTap: () {
Navigator.push(
context,
CupertinoPageRoute(
builder: (BuildContext ctx) => Maps(_searchResult[position])));
},
child:
Column(
children: <
Widget>[
Row(
children: <
Widget>[
Expanded(
child:Container(
height:150,
width: MediaQuery.of(context).size.width,
child: SizedBox(
child: FadeInImage(image: NetworkImage(_searchResult[position].thumbnail_name), placeholder: AssetImage("assets/640x360.png"),
fit: BoxFit.cover,),
),
)),
],
),
Container(
padding:
const EdgeInsets.all(5.0),
child:
Row(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
Container(
padding: const EdgeInsets.only(bottom: 1.0),
child: Text(
_searchResult[position].title,
style: TextStyle(fontFamily: 'Montserrat', fontSize: 13, fontWeight: FontWeight.bold),
),
),
Container(
padding: const EdgeInsets.only(bottom: 1.0),
child: Text(
_searchResult[position].address,
maxLines: 2,
style: TextStyle(fontFamily: 'Montserrat', fontSize: 10, color: Colors.black54),
),
),
Container(
padding: const EdgeInsets.only(bottom: 1.0),
child: _status != PermissionStatus.denied
? snapshot.hasData
? Text(
snapshot.data + " " + "km",
maxLines: 1,
style: TextStyle(fontFamily: 'Montserrat', fontSize: 10, fontWeight: FontWeight.bold, color: colorBlue),
)
: SizedBox(
child: CircularProgressIndicator(
valueColor: new AlwaysStoppedAnimation<Color>(
colorBlue,
),
strokeWidth: 1,
),
height: 5.0,
width: 5.0,
)
: Icon(
Icons.do_not_disturb,
color: Colors.red,
size: 15,
), ),
SizedBox(
height: 2,
),
Container(
child: Text(
_searchResult[position].price + " " + "USD",
style: TextStyle(
color: colorPink,
fontWeight: FontWeight.bold,
fontSize: 12,
fontFamily: 'Montserrat',
),
),
)
],
crossAxisAlignment: CrossAxisAlignment.start,
),
flex: 9,
),
Column(
children: <Widget>[
Container(
padding: const EdgeInsets.only(bottom: 0),
child: SmoothStarRating(
allowHalfRating: false,
onRatingChanged: (v) {
setState(() {});
},
starCount: 5,
rating: myrate,
size: 12.0,
filledIconData: Icons.star,
halfFilledIconData: Icons.star_half,
color: Colors.orange,
borderColor: Colors.orange,
spacing: 0.0)),
Text(
"(" + myrate.toStringAsFixed(1) + ")",
style: TextStyle(color: Colors.black, fontFamily: 'Montserrat', fontSize: 10, fontWeight: FontWeight.bold, fontStyle: FontStyle.normal),
),
],
)
],
),
)
],
)));
});
}))
])
)

Related

How do i return a container based on a list of item selected in flutter?

I have a list of items
List<String> items = [
"All",
"Jobs",
"Messages",
"Customers",
];
int current = 0;
And this list is directly responsible for my tab bar:
When i tap an item in the Tab bar i want to return a different container on each of them?
How do i go about this in flutter?
I tried returning an if statement just before the container but it seems i don't get the statement correctly.
this is the container i want to return if the item user select is All, and then put conditions in place for the rest items.
this is how i put the condition but it gives me this error
My return statement and code -
current = 0 ??
Container(
margin: const EdgeInsets.only(top: 30),
height: MediaQuery.of(context).size.height * 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
height: 10,
),
Text(
items[current],
style: GoogleFonts.laila(
fontWeight: FontWeight.w500,
fontSize: 30,
color: Colors.deepPurple),
),
],
),
),
current = 1 ?? Text('hello')
FULL WIDGET ADDED
class NotificationsView extends StatefulWidget {
#override
State<NotificationsView> createState() => _NotificationsViewState();
}
class _NotificationsViewState extends State<NotificationsView> {
final controller = Get.put(NotificationsController());
List<String> items = [
"All",
"Jobs",
"Messages",
"Customers",
];
int current = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Notifications".tr,
style: GoogleFonts.poppins(
color: Color(0xff000000),
fontSize: 16,
fontWeight: FontWeight.w600),
),
centerTitle: false,
backgroundColor: Colors.transparent,
elevation: 0,
automaticallyImplyLeading: false,
leadingWidth: 15,
leading: new IconButton(
icon: new Icon(Icons.arrow_back_ios, color: Color(0xff3498DB)),
onPressed: () => {Get.back()},
),
),
body: RefreshIndicator(
onRefresh: () async {
},
child: ListView(
primary: true,
children: <Widget>[
filter(),
],
),
),
);
}
Widget notificationsList() {
return Obx(() {
if (!controller.notifications.isNotEmpty) {
return CircularLoadingWidget(
height: 300,
onCompleteText: "Notification List is Empty".tr,
);
} else {
var _notifications = controller.notifications;
return ListView.separated(
itemCount: _notifications.length,
separatorBuilder: (context, index) {
return SizedBox(height: 7);
},
shrinkWrap: true,
primary: false,
itemBuilder: (context, index) {
var _notification = controller.notifications.elementAt(index);
if (_notification.data['message_id'] != null) {
return MessageNotificationItemWidget(
notification: _notification);
} else if (_notification.data['booking_id'] != null) {
return BookingNotificationItemWidget(
notification: _notification);
} else {
return NotificationItemWidget(
notification: _notification,
onDismissed: (notification) {
controller.removeNotification(notification);
},
onTap: (notification) async {
await controller.markAsReadNotification(notification);
},
);
}
});
}
});
}
Widget filter() {
return Container(
width: double.infinity,
margin: const EdgeInsets.all(5),
child: Column(
children: [
/// CUSTOM TABBAR
SizedBox(
width: double.infinity,
height: 60,
child: ListView.builder(
physics: const BouncingScrollPhysics(),
itemCount: items.length,
scrollDirection: Axis.horizontal,
itemBuilder: (ctx, index) {
return Column(
children: [
GestureDetector(
onTap: () {
setState(() {
current = index;
});
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.all(5),
decoration: BoxDecoration(
color: current == index
? Color(0xff34495E)
: Color(0xffF5F5F5),
borderRadius: BorderRadius.circular(11),
),
child: Center(
child: Padding(
padding: const EdgeInsets.only(
left: 10.0, right: 10.0, top: 5, bottom: 5),
child: Text(
items[index],
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color: current == index
? Colors.white
: Colors.grey),
),
),
),
),
),
],
);
}),
),
/// MAIN BODY
current = 0 ??
Container(
margin: const EdgeInsets.only(top: 30),
height: MediaQuery.of(context).size.height * 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
height: 10,
),
Text(
items[current],
style: GoogleFonts.laila(
fontWeight: FontWeight.w500,
fontSize: 30,
color: Colors.deepPurple),
),
Padding(
padding: const EdgeInsets.only(
left: 20.0, right: 20.0, top: 20.0, bottom: 20),
child: Column(
children: [
Stack(
children: [
Row(
children: [
Container(
decoration: BoxDecoration(
color: Color(0xffEFFAFF),
borderRadius:
BorderRadius.circular(20)),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Image.asset(
'assets/icon/suitcase.png'),
),
),
SizedBox(
width: 15,
),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
'New Job started ',
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Color(0xff151515)),
),
Text(
'Tailoring for John Cletus ',
style: GoogleFonts.poppins(
fontSize: 10,
fontWeight: FontWeight.w400,
color: Color(0xff151515)),
),
],
),
Spacer(),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
color: Color(0xffFFE8E8),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Urgent',
style: GoogleFonts.poppins(
color: Color(0xffC95E5E)),
),
),
),
],
),
],
),
Divider(
height: 5,
color: Color(0xffEFFAFF),
),
],
),
),
],
),
),
current = 1 ?? Text('hello')
],
),
);
}
}
You can use Builder if want to display different type of widget based on the current index.
Builder(
builder: (context) {
switch (current) {
case 0:
return Container(
margin: const EdgeInsets.only(top: 30),
height: MediaQuery.of(context).size.height * 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
height: 10,
),
Text(
items[current],
style: GoogleFonts.laila(
fontWeight: FontWeight.w500,
fontSize: 30,
color: Colors.deepPurple),
),
],
),
);
case 1:
return Text('Hello');
default:
return SizedBox.shrink();
}
},
);
Below approach will solve your problem. If you need further assistance, please feel free to comment.
int _currentIndex = 0;
var _containers = <Widget>[
AllContainer(),
JobsContainer(),
MessagesContainer(),
CustomerContainer(),
];
Widget _bottomTab() {
return BottomNavigationBar(
currentIndex: _currentIndex,
onTap: _onItemTapped, //
type: BottomNavigationBarType.fixed,
selectedLabelStyle: const TextStyle(color: Colors.blue),
selectedItemColor: WAPrimaryColor,
unselectedLabelStyle: const TextStyle(color: Colors.blue),
unselectedItemColor: Colors.grey,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(label: 'All'),
BottomNavigationBarItem(
label: 'Jobs'),
BottomNavigationBarItem(
label: 'Messages'),
BottomNavigationBarItem( label: 'Customer'),
],
);
}
void _onItemTapped(int index) async {
print('bottom index::: $index');
setState(() {
_currentIndex = index;
});
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
bottomNavigationBar: _bottomTab(),
body: Center(child: _containers.elementAt(_currentIndex)),
),
);
}
You can use conditional if on widget level,
like
/// MAIN BODY
if (current == 0)
Container(
margin: const EdgeInsets.only(top: 30),
height: MediaQuery.of(context).size.height * 1,
...
),
if (current == 1) Text('hello')
Also can be use else if
if (current == 0)
Container(
margin: const EdgeInsets.only(top: 30),
height: MediaQuery.of(context).size.height * 1,
) //you shouldnt put coma
else if (current == 1) Text('hello')
],
),
);
But creating a separate method will be better instead of putting it here
Widget getWidget(int index) {
/// MAIN BODY
if (current == 0) // or switch case
return Container(
margin: const EdgeInsets.only(top: 30),
height: MediaQuery.of(context).size.height * 1,
); //you shouldnt put coma
else if (current == 1) return Text('hello');
return Text("default");
}
And call the method getWidget(current).
Also there are some widget like PageView, IndexedStack will help to organize the code structure

Change a value from a List item and mantain it when changing pages on a page view

I get the length of the data in a page view.builder and then generate a List with all values being false (quantity = data length):
List<bool> isLockedList = List.generate(dataLength, (index) => false);
On a GestureDetector, on onTap, I have:
onTap: () {
setState(() {
isLockedList[index] = true;
});
print(isLockedList);
}
When I click on the item index 0 from the page view builder, which the length is 2, the List changes to [true, false]. When I go index 1, it changes to [false, true]. Why isn't it changing to [true, true]. Wasn't the value supposed to be overwritten?
When I change pages, without using the onTap, the List is reset to default values [false,false]
Entire code:
late final Stream<QuerySnapshot> _usersStream = FirebaseFirestore.instance
.collection('systems')
.doc(widget.systemRef)
.collection('matters')
.doc(widget.matterRef)
.collection('questions')
.snapshots();
#override
Widget build(BuildContext context) {
mediaQuery = MediaQuery.of(context).size;
int totalQuestion = 0;
int currentQuestion = 0;
return StreamBuilder<QuerySnapshot>(
stream: _usersStream,
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Scaffold(
body: Center(
child: Text('Algo deu errado'),
),
);
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
int dataLength = snapshot.data!.docs.length;
List<bool> isLockedList = List.generate(dataLength, (index) => false);
return Scaffold(
appBar: AppBar(
shadowColor: Colors.transparent,
backgroundColor: Colors.white,
leading: Navigator.canPop(context)
? IconButton(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
icon: const Icon(
Icons.chevron_left,
color: Colors.black,
size: 40,
),
onPressed: () => Navigator.of(context).pop(),
)
: null,
actions: [
Padding(
padding: EdgeInsets.only(right: mediaQuery.width *0.05),
child: Center(child: Text('$currentQuestion /$totalQuestion', style: const TextStyle(color: Colors.black),)),
),
],
),
body: SafeArea(
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.white,
child: PageView.builder(
onPageChanged: (value) {
print(isLockedList);
},
controller: _pageController,
itemCount: dataLength,
itemBuilder: (ctx, index) {
refIndex = index;
currentQuestion = index + 1;
totalQuestion = dataLength;
QueryDocumentSnapshot<Object?> output =
snapshot.data!.docs[index];
List<String> alternativesCode = List<String>.generate(
output['numberOfOptions'],
(int index) => 'option${index + 1}.code');
List<String> alternativesText = List<String>.generate(
output['numberOfOptions'],
(int index) => 'option${index + 1}.text');
imageUrl = output['image'];
return Container(
width: double.infinity,
padding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width * 0.05),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// SizedBox(
// width: mediaQuery.width,
// child: Text(
// '${index + 1}/$dataLength',
// textAlign: TextAlign.end,
// style: const TextStyle(
// fontSize: 18, fontWeight: FontWeight.w600),
// ),
// ),
Container(
constraints: BoxConstraints(
maxHeight: mediaQuery.height * 0.16,
minHeight: mediaQuery.height * 0.05),
child: AutoSizeText(
output['title'],
maxLines: 4,
textAlign: TextAlign.start,
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 23),
),
),
SizedBox(height: mediaQuery.height * 0.03),
const SizedBox(
height: 10,
),
imageUrl.isNotEmpty
? Container(
alignment: Alignment.center,
child: Image.network(imageUrl,
height: mediaQuery.height * 0.2))
: SizedBox(
height: mediaQuery.height * 0.05,
),
SizedBox(
height: mediaQuery.height * 0.03,
),
Container(
constraints:
BoxConstraints(maxHeight: mediaQuery.height * 0.1, maxWidth: mediaQuery.width * 0.9),
child: AutoSizeText(
output['subtitle'],
maxLines: 2,
textAlign: TextAlign.start,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15,
fontStyle: FontStyle.italic),
),
),
SizedBox(
height: mediaQuery.height * 0.02,
),
Container(
height: mediaQuery.height * 0.37,
width: double.infinity,
color: Colors.white,
child: ListView.builder(
physics: const NeverScrollableScrollPhysics(),
itemCount: alternativesText.length,
itemBuilder: (ctx, i) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
child: GestureDetector(
child: Container(
height: mediaQuery.height * 0.07,
decoration: BoxDecoration(
boxShadow: const [
BoxShadow(
color: Colors.grey,
blurRadius: 3,
// Shadow position
),
],
border: Border.all(
width: 3, color: Colors.grey),
borderRadius: BorderRadius.circular(10),
color: Colors.grey[100],
),
// width: mediaQuery.width,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10),
child: Row(
children: [
Text(
'${output[alternativesCode[i]]}',
style: TextStyle(
color: Colors.grey.shade800,
fontWeight: FontWeight.w600,
fontSize: 20),
),
Container(
padding:
const EdgeInsets.only(left: 5),
alignment: Alignment.centerLeft,
width: mediaQuery.width * 0.78,
height: mediaQuery.height * 0.07,
// constraints: BoxConstraints(maxWidth: mediaQuery.width * 0.8, minWidth: mediaQuery),
child: AutoSizeText(
output[alternativesText[i]],
maxLines: 2,
textAlign: TextAlign.justify,
style: const TextStyle(
color: Colors.black,
fontWeight: FontWeight.w500,
fontSize: 15),
),
),
],
),
),
),
onTap: () {
setState(() {
isLockedList[index] = true;
});
print(isLockedList);
}),
);
},
),
),
],
),
);
},
),
),
),
);
},
);
}
}
Follow these steps.
Declare isLockedList outside the build method as a nullable.
Set isLockedList only when the value is null in the StreamBuilder.
Code:
List<bool>? isLockedList;
#override
Widget build(BuildContext context){
....
return StreamBuilder<QuerySnapshot>(
builder: (context, snapshot) {
...
if (snapshot.hasError) {
return const Scaffold(
body: Center(
child: Text('Algo deu errado'),
),
);
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
int dataLength = snapshot.data!.docs.length;
if(isLockedList == null){
isLockedList = List.generate(dataLength, (index) => false);
}
....
}
);
....
}

No data from sever API's is not showing on Listview using flutter

I'm fetching data from server APIs, The data is being successfully fetched from the server but the issue is that when the data is provided to Listview it cant be shown. How can I show the data on Listview in a flutter/dart?
Following is the code for fetching data from server API's
List<String> jobTitles = [];
List officeNames = [ ];
List officeLocations = [ ];
List jobTypes = [ ];
Future getJobsData() async {
var response = await http
.get(Uri.https('hospitality92.com', 'api/jobsbycategory/All'));
Map<String, dynamic> map = json.decode(response.body);
List<dynamic> jobData = map["jobs"];
if (jobTitles.length != 0) {
officeNames.clear();
jobTitles.clear();
officeLocations.clear();
jobTypes.clear();
}
for (var i = 0; i < jobData.length; i++) {
jobTitles.add(jobData[i]["title"]);
officeNames.add(jobData[i]["company_name"]);
officeLocations.add(jobData[i]["company_name"]);
jobTypes.add(jobData[i]["type"]);
}
/* print(jobTitles);
print(officeNames);
print(officeLocations);
print(jobTypes);*/
}
Here is the design code that I wanted to show:
Widget listCard(jobTitle, officeName, location, jobType, onPress) {
return Container(
child: InkWell(
onTap: onPress,
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xC000000), Color(0xC000000)])),
child: ListTile(
leading: CircleAvatar(
radius: 30,
child: Image.asset(
"assets/ic_login.png",
height: 28,
width: 28,
),
),
title: Text(
jobTitle,
style: TextStyle(
fontSize: 16,
color: Colors.lightBlue,
fontFamily: 'Montserrat',
fontWeight: FontWeight.w500),
),
subtitle: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Row(
children: [
Icon(
Icons.home_outlined,
color: Colors.black,
size: 16,
),
Text(
officeName,
style: TextStyle(fontSize: 10),
),
],
),
SizedBox(
width: 10,
),
Row(
children: [
Icon(
Icons.location_pin,
color: Colors.blueGrey,
size: 16,
),
SizedBox(
width: 2,
),
Text(
location,
style: TextStyle(fontSize: 10),
),
],
),
SizedBox(
width: 10,
),
Row(
children: [
Container(
margin: const EdgeInsets.fromLTRB(0, 4, 0, 0),
decoration: BoxDecoration(
gradient: LinearGradient(colors: [
Colors.lightBlueAccent,
Colors.lightBlueAccent
])),
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Text(
jobType,
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: Colors.white),
),
),
),
],
)
//ElevatedButton(onPressed: () { }, child: Text("Full Time", style: TextStyle(fontSize: 10),),),
],
),
),
),
),
),
],
),
),
);
}
Here is the listview code
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: jobTitle.length,
itemBuilder: (context, index) {
return listCard(jobTitles[index], officeNames[index],
officeLocations[index], jobTypes[index], () {});
}),
If I provide the static data to list it will show on listview, but dynamic data is not being shown.
Try To below Code Your problem has been solved:
Create API Call Function
Future<List<dynamic>> getJobsData() async {
String url = 'https://hospitality92.com/api/jobsbycategory/All';
var response = await http.get(Uri.parse(url), headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
});
return json.decode(response.body)['jobs'];
}
Write/Create your Widget :
Center(
child: FutureBuilder<List<dynamic>>(
future: getJobsData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
var title = snapshot.data[index]['title'];
var company = snapshot.data[index]['company_name'];
var skills = snapshot.data[index]['skills'];
var description = snapshot.data[index]['description'];
var positions = snapshot.data[index]['positions'];
return Card(
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.green.shade300,
),
borderRadius: BorderRadius.circular(15.0),
),
child: ListTile(
leading: Text(skills),
title: Text(title),
subtitle: Text(
company + '\n' + description,
),
trailing: Text(positions),
),
);
},
),
);
}
return CircularProgressIndicator();
},
),
),
Your Screen Look Like

How to solve "a build function has returned null" in flutter app?

App was working perfectly before and then I had to make some changes to allow or restrict calling feature in the app based on subscription level of the user, by passing the variable value from one screen to another using provider.
one Screen 1 i am using :
Future<void> _verifyPuchase(String id) async {
PurchaseDetails purchase = _hasPurchased(id);
if (purchase != null && purchase.status == PurchaseStatus.purchased) {
print(purchase.productID);
if (Platform.isIOS) {
await _iap.completePurchase(purchase);
print('Achats antérieurs........$purchase');
isPuchased = true;
}
isPuchased = true;
checkIsPurchsed(isPurchsed: isPuchased);
} else {
isPuchased = false;
checkIsPurchsed(isPurchsed: isPuchased);
}
}
and have i have a class on screen 1:
class checkIsPurchsed with ChangeNotifier{
bool isPurchsed;
checkIsPurchsed({this.isPurchsed});
notifyListeners();
}
and on screen 5 I have:
Consumer<checkIsPurchsed>(
builder: (context,isPurchsed,child){
return isPurchsed.isPurchsed ? IconButton(
icon: Icon(Icons.call), onPressed: () => onJoin("AudioCall"),
):Center(child: Text(
'Sorry you have not subscribe the package',
),);
},
),
Consumer<checkIsPurchsed>(
builder: (context,isPurchsed,child){
return isPurchsed.isPurchsed ? IconButton(
icon: Icon(Icons.video_call), onPressed: () => onJoin("VideoCall"),
):Center(child: Text(
'Sorry you have not subscribe the package',
),);
},
),
on screen 5 when i try to open a chat this is what i am getting :
the icon buttons on which i am checking the purchase status appear when chat is opened , but after adding the above mentioned modifications the chat itself isnt opening and instead i am getting the red screen.
Update 1:
class ChatPage extends StatefulWidget {
final User sender;
final String chatId;
final User second;
ChatPage({this.sender, this.chatId, this.second});
#override
_ChatPageState createState() => _ChatPageState();
}
class _ChatPageState extends State<ChatPage> {
bool isBlocked = false;
final db = Firestore.instance;
CollectionReference chatReference;
final TextEditingController _textController = new TextEditingController();
bool _isWritting = false;
final _scaffoldKey = GlobalKey<ScaffoldState>();
//Ads _ads = new Ads();
#override
void initState() {
//_ads.myInterstitial()
//..load()
//..show();
print("object -${widget.chatId}");
super.initState();
chatReference =
db.collection("chats").document(widget.chatId).collection('messages');
checkblock();
}
var blockedBy;
checkblock() {
chatReference.document('blocked').snapshots().listen((onData) {
if (onData.data != null) {
blockedBy = onData.data['blockedBy'];
if (onData.data['isBlocked']) {
isBlocked = true;
} else {
isBlocked = false;
}
if (mounted) setState(() {});
}
// print(onData.data['blockedBy']);
});
}
List<Widget> generateSenderLayout(DocumentSnapshot documentSnapshot) {
return <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Container(
child: documentSnapshot.data['image_url'] != ''
? InkWell(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
new Container(
margin: EdgeInsets.only(
top: 2.0, bottom: 2.0, right: 15),
child: Stack(
children: <Widget>[
CachedNetworkImage(
placeholder: (context, url) => Center(
child: CupertinoActivityIndicator(
radius: 10,
),
),
errorWidget: (context, url, error) =>
Icon(Icons.error),
height:
MediaQuery.of(context).size.height * .65,
width: MediaQuery.of(context).size.width * .9,
imageUrl:
documentSnapshot.data['image_url'] ?? '',
fit: BoxFit.fitWidth,
),
Container(
alignment: Alignment.bottomRight,
child:
documentSnapshot.data['isRead'] == false
? Icon(
Icons.done,
color: secondryColor,
size: 15,
)
: Icon(
Icons.done_all,
color: primaryColor,
size: 15,
),
)
],
),
height: 150,
width: 150.0,
color: secondryColor.withOpacity(.5),
padding: EdgeInsets.all(5),
),
Padding(
padding: const EdgeInsets.only(right: 10),
child: Text(
documentSnapshot.data["time"] != null
? DateFormat.yMMMd()
.add_jm()
.format(documentSnapshot.data["time"]
.toDate())
.toString()
: "",
style: TextStyle(
color: secondryColor,
fontSize: 13.0,
fontWeight: FontWeight.w600,
)),
)
],
),
onTap: () {
Navigator.of(context).push(
CupertinoPageRoute(
builder: (context) => LargeImage(
documentSnapshot.data['image_url'],
),
),
);
},
)
: Container(
padding: EdgeInsets.symmetric(
horizontal: 15.0, vertical: 10.0),
width: MediaQuery.of(context).size.width * 0.65,
margin: EdgeInsets.only(
top: 8.0, bottom: 8.0, left: 80.0, right: 10),
decoration: BoxDecoration(
color: primaryColor.withOpacity(.1),
borderRadius: BorderRadius.circular(20)),
child: Column(
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Container(
child: Text(
documentSnapshot.data['text'],
style: TextStyle(
color: Colors.black87,
fontSize: 16.0,
fontWeight: FontWeight.w600,
),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text(
documentSnapshot.data["time"] != null
? DateFormat.MMMd()
.add_jm()
.format(documentSnapshot
.data["time"]
.toDate())
.toString()
: "",
style: TextStyle(
color: secondryColor,
fontSize: 13.0,
fontWeight: FontWeight.w600,
),
),
SizedBox(
width: 5,
),
documentSnapshot.data['isRead'] == false
? Icon(
Icons.done,
color: secondryColor,
size: 15,
)
: Icon(
Icons.done_all,
color: primaryColor,
size: 15,
)
],
),
],
),
],
)),
),
],
),
),
];
}
_messagesIsRead(documentSnapshot) {
return <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
InkWell(
child: CircleAvatar(
backgroundColor: secondryColor,
radius: 25.0,
child: ClipRRect(
borderRadius: BorderRadius.circular(90),
child: CachedNetworkImage(
imageUrl: widget.second.imageUrl[0] ?? '',
useOldImageOnUrlChange: true,
placeholder: (context, url) => CupertinoActivityIndicator(
radius: 15,
),
errorWidget: (context, url, error) => Icon(Icons.error),
),
),
),
onTap: () => showDialog(
barrierDismissible: false,
context: context,
builder: (context) {
return Info(widget.second, widget.sender, null);
}),
),
],
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
child: documentSnapshot.data['image_url'] != ''
? InkWell(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
new Container(
margin: EdgeInsets.only(
top: 2.0, bottom: 2.0, right: 15),
child: CachedNetworkImage(
placeholder: (context, url) => Center(
child: CupertinoActivityIndicator(
radius: 10,
),
),
errorWidget: (context, url, error) =>
Icon(Icons.error),
height: MediaQuery.of(context).size.height * .65,
width: MediaQuery.of(context).size.width * .9,
imageUrl:
documentSnapshot.data['image_url'] ?? '',
fit: BoxFit.fitWidth,
),
height: 150,
width: 150.0,
color: Color.fromRGBO(0, 0, 0, 0.2),
padding: EdgeInsets.all(5),
),
Padding(
padding: const EdgeInsets.only(right: 10),
child: Text(
documentSnapshot.data["time"] != null
? DateFormat.yMMMd()
.add_jm()
.format(documentSnapshot.data["time"]
.toDate())
.toString()
: "",
style: TextStyle(
color: secondryColor,
fontSize: 13.0,
fontWeight: FontWeight.w600,
)),
)
],
),
onTap: () {
Navigator.of(context).push(CupertinoPageRoute(
builder: (context) => LargeImage(
documentSnapshot.data['image_url'],
),
));
},
)
: Container(
padding: EdgeInsets.symmetric(
horizontal: 15.0, vertical: 10.0),
width: MediaQuery.of(context).size.width * 0.65,
margin: EdgeInsets.only(top: 8.0, bottom: 8.0, right: 10),
decoration: BoxDecoration(
color: secondryColor.withOpacity(.3),
borderRadius: BorderRadius.circular(20)),
child: Column(
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Container(
child: Text(
documentSnapshot.data['text'],
style: TextStyle(
color: Colors.black87,
fontSize: 16.0,
fontWeight: FontWeight.w600,
),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text(
documentSnapshot.data["time"] != null
? DateFormat.MMMd()
.add_jm()
.format(documentSnapshot
.data["time"]
.toDate())
.toString()
: "",
style: TextStyle(
color: secondryColor,
fontSize: 13.0,
fontWeight: FontWeight.w600,
),
),
],
),
],
),
],
)),
),
],
),
),
];
}
List<Widget> generateReceiverLayout(DocumentSnapshot documentSnapshot) {
if (!documentSnapshot.data['isRead']) {
chatReference.document(documentSnapshot.documentID).updateData({
'isRead': true,
});
return _messagesIsRead(documentSnapshot);
}
return _messagesIsRead(documentSnapshot);
}
generateMessages(AsyncSnapshot<QuerySnapshot> snapshot) {
return snapshot.data.documents
.map<Widget>((doc) => Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: doc.data['type'] == "Call"
? [
Text(doc.data["time"] != null
? "${doc.data['text']} : " +
DateFormat.yMMMd()
.add_jm()
.format(doc.data["time"].toDate())
.toString() +
" by ${doc.data['sender_id'] == widget.sender.id ? "You" : "${widget.second.name}"}"
: "")
]
: doc.data['sender_id'] != widget.sender.id
? generateReceiverLayout(
doc,
)
: generateSenderLayout(doc)),
))
.toList();
}
#override
Widget build(BuildContext context) {
ChangeNotifierProvider<checkIsPurchsed>(
create: (context)=>checkblock(),
child: Scaffold(
key: _scaffoldKey,
backgroundColor: Colors.white,
appBar: AppBar(
centerTitle: true,
elevation: 0,
title: Text(widget.second.name),
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
color: Colors.white,
onPressed: () => Navigator.pop(context),
),
actions: <Widget>[
Consumer<checkIsPurchsed>(
builder: (context,isPurchsed,child){
return isPurchsed.isPurchsed ? IconButton(
icon: Icon(Icons.call), onPressed: () => onJoin("AudioCall"),
):Center(child: Text(
'Sorry you have not subscribe the package',
),);
},
),
Consumer<checkIsPurchsed>(
builder: (context,isPurchsed,child){
return isPurchsed.isPurchsed ? IconButton(
icon: Icon(Icons.video_call), onPressed: () => onJoin("VideoCall"),
):Center(child: Text(
'Sorry you have not subscribe the package',
),);
},
),
}
The problematic area is:
#override
Widget build(BuildContext context) {
ChangeNotifierProvider<checkIsPurchsed>(
There's no return in front of ChangeNotifierProvider, so it doesn't return a Widget. Correct would be:
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<checkIsPurchsed>(

Flutter combo box item in list view

I'm trying to make a combobox and when I select an item, I want it to be added in a listview when a button is pressed.
I tried multiple solutions, but none seems to work, as far as I did, I could make a input field and add the items manually, but I can't do it with a combobox ( without letting the user write them manually ).
Here is what I did:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:searchable_dropdown/searchable_dropdown.dart';
class LocationTab extends StatefulWidget {
#override
_LocationTabState createState() => _LocationTabState();
}
class _LocationTabState extends State<LocationTab> {
List<String> mylist = List();
List<ParentCategoryComboBox> _visibility =
ParentCategoryComboBox.getParentCategory();
List<DropdownMenuItem<ParentCategoryComboBox>> _dropdownMenuItems;
List<PlatformReachComboBox> _platformReach =
PlatformReachComboBox.getPlatformReach();
List<DropdownMenuItem<PlatformReachComboBox>> _dropdownPlatformReach;
PlatformReachComboBox _selectedPlatformReach;
ParentCategoryComboBox _selectedVisibility;
#override
void initState() {
_dropdownMenuItems = buildDropDownMenuItems(_visibility);
_selectedVisibility = _dropdownMenuItems[0].value;
_dropdownPlatformReach =
buildDropdownMenuItemsPlatformReach(_platformReach);
_selectedPlatformReach = _dropdownPlatformReach[0].value;
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(top: 10.0, left: 20.0, right: 20.0),
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.vertical,
child: Column(
children: <Widget>[
SizedBox(
height: 20,
),
Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
"Select visibility:",
style: TextStyle(
color: Colors.indigoAccent,
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
],
),
DropdownButton(
icon: Icon(
Icons.visibility,
color: Colors.black45,
),
isExpanded: true,
value: _selectedVisibility,
items: _dropdownMenuItems,
onChanged: (ParentCategoryComboBox selectedVisibility) {
setState(() {
_selectedVisibility = selectedVisibility;
});
},
),
SizedBox(
height: 35,
),
Container(
padding: new EdgeInsets.symmetric(horizontal: 5.0),
decoration: BoxDecoration(
border: Border.all(
width: 1,
color: Colors.grey,
),
borderRadius: BorderRadius.circular((10))),
child: Column(
children: <Widget>[
SizedBox(
height: 10,
),
Align(
alignment: Alignment.centerLeft,
child: Text(
"Select platform reach:",
style: TextStyle(
color: Colors.indigoAccent,
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
SizedBox(
height: 20,
),
Row(
children: <Widget>[
Expanded(
child: SearchableDropdown(
isExpanded: true,
value: _selectedPlatformReach,
items: _dropdownPlatformReach,
isCaseSensitiveSearch: false,
onChanged:
(PlatformReachComboBox selectedPlatformReach) {
setState(() {
_selectedPlatformReach = selectedPlatformReach;
});
},
),
flex: 2,
),
Expanded(
child: Container(
height: 50.0,
width: 80,
child: Material(
borderRadius: BorderRadius.circular(20.0),
shadowColor: Colors.blue,
color: Colors.deepPurpleAccent,
elevation: 0.0,
child: GestureDetector(
onTap: () {
setState(() {
mylist.add(_selectedPlatformReach.toString());
});
},
child: Center(
child: Text(
'ADD',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
),
),
flex: 0,
),
],
),
SizedBox(
height: 10,
),
Align(
alignment: Alignment.centerLeft,
child: Text(
"Added:",
style: TextStyle(
color: Colors.indigoAccent,
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
SizedBox(
height: 10,
),
ListView.builder(
padding: EdgeInsets.only(left: 10),
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: mylist.length,
itemBuilder: (BuildContext ctxt, int Index) {
return Text(
mylist[Index]
);
},
),
// ListView.builder(
// padding: EdgeInsets.only(left: 10),
// scrollDirection: Axis.vertical,
// shrinkWrap: true,
// itemCount: _platformReach.length,
// itemBuilder: (BuildContext ctxt, int Index) {
// return Text(
// "Galati"
// );
//// return DropdownButton(
//// value: _selectedPlatformReach.toString(),
//// items: _dropdownPlatformReach,
//// onChanged: (value) {
//// _selectedPlatformReach = value;
//// setState(() {});
//// },
//// hint: Text('Select drowdown'),
//// );
//// return new Text(_dropdownPlatformReach[Index].value);
// },
// ),
],
),
),
],
),
),
);
}
}
Mock data class:
import 'package:flutter/material.dart';
class PlatformReachComboBox {
String name;
String hint;
PlatformReachComboBox(this.name, this.hint);
static List<PlatformReachComboBox> getPlatformReach() {
return <PlatformReachComboBox>[
PlatformReachComboBox('Jud Galati', '(RO, [Galati] County)'),
PlatformReachComboBox('Jud Braila', '(RO, [Braila] County)'),
PlatformReachComboBox('Jud Prahova', '(RO, [Ploiesti] County)'),
PlatformReachComboBox('Jud Maramures', '(RO, [Baia Mare] County)'),
];
}
}
List<DropdownMenuItem<PlatformReachComboBox>>
buildDropdownMenuItemsPlatformReach(List platforms) {
List<DropdownMenuItem<PlatformReachComboBox>> items = List();
for (PlatformReachComboBox platform in platforms) {
items.add(
DropdownMenuItem(
value: platform,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
platform.name,
style: TextStyle(fontWeight: FontWeight.bold),
textAlign: TextAlign.start,
),
Text(
platform.hint,
style:
TextStyle(fontWeight: FontWeight.normal, color: Colors.grey),
textAlign: TextAlign.end,
)
],
),
),
);
}
return items;
}
And this is where I encounter the problem, I don't know what to return in ListView for me pressing the button, and then the item to be added in there:
ListView.builder(
padding: EdgeInsets.only(left: 10),
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: _platformReach.length,
itemBuilder: (BuildContext ctxt, int Index) {
return Text(
"Galati"
);
},
),
please try this way ... define a list
List<String> mylist = List();
and use it below
ListView.builder(
padding: EdgeInsets.only(left: 10),
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: mylist.length,
itemBuilder: (BuildContext ctxt, int Index) {
return Text(
mylist[Index]
);
},
),
and After button Clicked
setState(() {
mylist.add(_selectedVisibility.name);
});