Related
I'm trying to write an app that will detect Barcode ID. Once detected, it will fetch value in my Firebase Database and display them inside my Widget. I want my widget to be dynamic since i don't know how many items could be inside each ID. So i tried using FirebaseAnimatedList class. Issue is i can't get my Widget show up in my page at all.
Here's my code
import 'dart:async';
import 'package:firebase_database/ui/firebase_animated_list.dart';
import 'package:flutter/material.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:logistec/widget/result_page/productlist.dart';
class Scanning_Result_Page extends StatefulWidget {
Scanning_Result_Page(this.phyid, {Key? key}) : super(key: key);
String phyid;
#override
State<Scanning_Result_Page> createState() => _Scanning_Result_PageState();
}
class _Scanning_Result_PageState extends State<Scanning_Result_Page> {
late String productcode;
late String productname;
late int quantity;
late Query _ref =
FirebaseDatabase.instance.ref().child('Database').child(widget.phyid);
//firebase structure currently goes like this
//PHYID
//|---number
//|-----items_name
//|-----items_codes etc...
//Therefore i need it to first fetch PHYID
//then after that, use for loop from 0 to the full lenght of that ID
//
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: PreferredSize(
preferredSize: Size(40, 40),
child: AppBar(
backgroundColor: Colors.amber.shade400,
)),
body: Container(
height: double.infinity,
child: FirebaseAnimatedList(
shrinkWrap: true,
query: _ref.equalTo(widget.phyid),
itemBuilder: (BuildContext context, DataSnapshot snapshot,
Animation<double> animation, int index) {
Map database = snapshot.value as Map;
if (database != null) {
//result = key - phyid | value - 0?
return ProductList(
productcode: 'Test 1', //will change this later. just need it to work for now.
productname: 'Test 1',
serial: 'Test 1',
quantity: 1,
phyid_result: widget.phyid,
);
} else {
return Text("no data");
}
return CircularProgressIndicator();
},
),
),
);
}
}
And here's my Widget page. (I don't think it's related to my issue but i'll include them regardless.)
import 'package:flutter/material.dart';
class ProductList extends StatelessWidget {
ProductList({
Key? key,
required this.productcode,
required this.productname,
required this.quantity,
required this.phyid_result,
required this.serial,
}) : super(key: key);
final String productcode;
final String productname;
final int quantity;
final String phyid_result;
final String serial;
//The Look in my head
//Each Container will have
///////////////////////////////////
///ProductCode /
///ProductName /
/// /
/// ///////////////////////////////
/// Quantity/
/// ///////////////////////////////
final appBar = AppBar();
#override
Widget build(BuildContext context) {
final screenSize = MediaQuery.of(context);
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
resizeToAvoidBottomInset: false,
body: CustomScrollView(
scrollDirection: Axis.vertical,
slivers: [
SliverList(
delegate: SliverChildListDelegate([
Container(
padding: const EdgeInsets.all(15.0),
alignment: Alignment.center,
color: Colors.black,
height: 70.0,
child: Text(
phyid_result,
style: const TextStyle(
color: Colors.white,
fontSize: 25,
),
),
),
Container(
height: screenSize.size.height,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade600)),
child: IntrinsicHeight(
child: Column(
//mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
padding: EdgeInsets.all(5),
child: Text(
productcode,
style: const TextStyle(fontSize: 20),
),
),
Container(
padding: EdgeInsets.all(5),
width: screenSize.size.width,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey.shade200,
strokeAlign: StrokeAlign.inside)),
child: Text(
productname,
style: const TextStyle(fontSize: 20),
),
),
Container(
padding: EdgeInsets.all(5),
width: screenSize.size.width,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey.shade200,
strokeAlign: StrokeAlign.inside)),
child: Text(
serial,
style: const TextStyle(fontSize: 20),
),
),
Align(
alignment: Alignment.topRight,
child: Flexible(
fit: FlexFit.loose,
child: SizedBox(
width: 90,
child: Container(
decoration: BoxDecoration(
border:
Border.all(color: Colors.grey.shade200),
),
padding: EdgeInsets.all(5),
child: Text(
'Quantity : \n\v${quantity}',
style: TextStyle(fontSize: 18),
textAlign: TextAlign.right,
)),
),
),
)
],
),
),
),
]))
],
),
),
);
}
}
The Scaffold part works. But everything inside FirebaseAnimated List all the way to CircularProgressIndicator doesn't work at all. It didn't even return if else statement. Just empty blank page with Scaffold.
The Widget itself will work fine if i remove everything out, and return only the ProductList widget itself. I tried searching on Google and didn't find anyone having issue like me. So i think i'm stuck. Does anyone know what could be the issue? Thanks for the assistance in advance!
So i solve my own issue.
It turns out that my Widget is the actual root cause. I don't think SliverList is playing well with FirebaseAnimatedList (maybe because they are doing essentially the same thing?) So i refactor and remove everything related to SliverList.
Widget build(BuildContext context) {
final screenSize = MediaQuery.of(context);
return Container(
decoration:
BoxDecoration(border: Border.all(color: Colors.grey.shade600)),
child: Column(
//mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
padding: EdgeInsets.all(5),
child: Text(
productcode,
style: const TextStyle(fontSize: 20),
),
),
Container(
padding: EdgeInsets.all(5),
width: screenSize.size.width,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey.shade200,
strokeAlign: StrokeAlign.inside)),
child: Text(
productname,
style: const TextStyle(fontSize: 20),
),
),
Container(
padding: EdgeInsets.all(5),
width: screenSize.size.width,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey.shade200,
strokeAlign: StrokeAlign.inside)),
child: Text(
serial,
style: const TextStyle(fontSize: 20),
),
),
Align(
alignment: Alignment.topRight,
child: Flexible(
fit: FlexFit.loose,
child: SizedBox(
width: 90,
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade200),
),
padding: EdgeInsets.all(5),
child: Text(
'Quantity : \n\v${quantity}',
style: TextStyle(fontSize: 18),
textAlign: TextAlign.right,
)),
),
),
)
],
),
);
Then i reimplemented it into my pages. Now it works as expected. all is well again!
I'm having some trouble simply sending data from AlertDialog to our mainscreen that is _MyHomePageState and into the defined Text widget saying "Paste here!".
I also have a few questions regarding passing data in this scenario (where we are sending data from pop up window to same or other screen):
1.) Is using AlertDialog widget in this scenario even the correct technique?
2.) What's the correct method when passing input data and displaying it, do we first save it into an array and then retrieve value from array? Do we use stack or some other array method?
3.) Why or why not should I put my logic into the _MyHomePage class or it doesn't matter?
4.) Should I use custom component that I call from some other file for pop up button/window? (feels like there's just a bunch of stuff code wise that could be elsewhere on its own in its own file)
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
Future<void> showInformationDialog(BuildContext context) async {
return await showDialog(context: context,
builder: (context) {
final TextEditingController _textEditingController = TextEditingController();
bool isChecked = false;
final TextEditingController _testEE = TextEditingController();
return StatefulBuilder(builder: (context, setState) {
return AlertDialog(
content: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
controller: _testEE,
validator: (value) {
//check if value is empty
return value.isNotEmpty ? null : "Invalid Field";
},
decoration: InputDecoration(hintText: "Enter text"),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Choice"),
Checkbox(value: isChecked, onChanged: (checked) {
setState((){
isChecked = checked;
});
})
],
)
],
)),
actions: <Widget>[
TextButton(
child: Text("Okay"),
onPressed: () {
var _test = _testEE.text;
print("test?" + _test);
if(_formKey.currentState.validate()) {
Navigator.of(context).pop();
}
},
)
],
);
});
});
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.teal[800],
body: ListView(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 15.0, left: 40.0),
child: Row(
children: <Widget>[
Text('Check List',
style: TextStyle(
fontFamily: 'Montserrat',
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 25.0)),
IconButton(
padding: EdgeInsets.only(left: 140.0),
icon: Icon(Icons.menu),
color: Colors.white,
onPressed: () {},
)
],
),
),
SizedBox(height: 15.0),
Container(
height: MediaQuery.of(context).size.height - 100.0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(topLeft: Radius.circular(75.0)),
),
child: ListView(
primary: false,
padding: EdgeInsets.only(left: 35.0, right: 35.0),
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 25.0),
child: Container(
height: MediaQuery.of(context).size.height - 300.0,
child: ListView(children: [
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Text('Test 1',
style: TextStyle(
fontFamily: 'Montserrat',
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 15.0)),
),
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Text("Paste here!",
style: TextStyle(
fontFamily: 'Montserrat',
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 15.0)),
),
//_buildFoodItem('assets/plate5.png', 'Berry bowl', '\$24.00')
]))),
//Button Row
Padding(
padding: const EdgeInsets.only(top: 60.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
SizedBox(
width: 75.0,
height: 75.0,
child: ElevatedButton(
onPressed: () async {
await showInformationDialog(context);
},
child: Text("Add"),
style: ElevatedButton.styleFrom(
side: BorderSide(width: 2.0, color: Colors.black),
shape: CircleBorder(),
padding: EdgeInsets.all(20),
primary: Colors.white, // <-- button color
onPrimary: Colors.black, // <-- splash color
),
),
),
Returning a parameter from a pushed screen or dialog is simple.
The method pop() you used accepts a optional result parameter:
Navigator.pop(context, _test); // _test will be returned
The documentation of this method can be read here.
Use this to return the previous screen the value you want. You need to use await and keep the result in a variable:
onPressed: () async {
String result = await showInformationDialog(context);
setState((){
myText=result;
});
},
Remember to declare myText inside your State class:
class _MyHomePageState extends State<MyHomePage> {
String myText = ''; // add this.
And use this variable where you need it:
[...]
child: Text(myText,
[...]
You can read more about it in this cookbook from Flutter team.
Ps: About the other questions, most of them are opinion based. They are project decisions and each have pros and cons. I believe that if this is a simple project it won't matter so much. If you need to dive deeper in these topics I suggest you to create other questions, since they are unrelated to this one.
Container(
child: Column(
children: <Widget>[
Container(
alignment: Alignment.topLeft,
padding: EdgeInsets.only(left: 10.0),
child: Text("Random Text",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black)),
),
Container(
alignment: Alignment.topLeft,
padding: EdgeInsets.all(10.0),
child: Text("Owner",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.grey)),
),
],
),
),
I don't know if it's an easy way. But for a simple reusable widget, you can place your widget inside a StatelessWidget or a StatefulWidget.
Here's the example:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Column(
children: <Widget>[
MyReusableWidget('Nikola Tesla', 'Owner'), //Input the name and role variable when you call the widget
MyReusableWidget('Albert Einstein', 'Developer'),
MyReusableWidget('Isaac Newton', 'Technician'),
],
),
),
);
}
}
class MyReusableWidget extends StatelessWidget {
final String name; // provide a place for the input's data
final String role;
MyReusableWidget(this.name, this.role);
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
Container(
alignment: Alignment.topLeft,
padding: EdgeInsets.only(left: 10.0),
child: Text(
name, // This is where you place your 'name' data
style: TextStyle(
fontWeight: FontWeight.bold, color: Colors.black),
),
),
Container(
alignment: Alignment.topLeft,
padding: EdgeInsets.all(10.0),
child: Text(
role, // This is where you place your 'role' data
style: TextStyle(
fontWeight: FontWeight.bold, color: Colors.grey),
),
),
],
),
);
}
}
I'm creating a widget called MyReusableWidget. I am gonna call that widget inside my MyApp 3 times. And then each widget should provide different names and roles.
So inside my MyReusableWidget, I provide two String data-types called name and role to store my data when I call the widget.
final String name; // provide a place for the input's data
final String role;
MyReusableWidget(this.name, this.role);
And then I want to place my name and role variable inside a Text widget:
child: Text(
name, // This is where you place your 'name' data
style: TextStyle(
fontWeight: FontWeight.bold, color: Colors.black),
),
and:
child: Text(
role, // This is where you place your 'role' data
style: TextStyle(
fontWeight: FontWeight.bold, color: Colors.grey),
),
After that, inside my MyApp widget, I can call MyReusableWidget as much as I want and provide different name and role value on each widget.
Column(
children: <Widget>[
MyReusableWidget('Nikola Tesla', 'Owner'), //Input the name and role variable when you call the widget
MyReusableWidget('Albert Einstein', 'Developer'),
MyReusableWidget('Isaac Newton', 'Technician'),
],
),
Result:
And that's it.
You can store any kind of data-type on it (String, int, double, etc).
I hope it will be helpful.
I am new to Flutter. I am trying to build a Quiz App. Now, I am on the Quiz Screen, and then a quiz has multiple questions. I am showing the question title along with the answers, and when someone clicks on the answer, I am updating the QuestionView again with the new question data. These are stateful widgets, and when the result is fetched I am using setState to update the widget, and if I place a break point there I can see that the things are updated, but that is not rendered on the screen or the view is not changed, it has same title, answers and everything. I am using an optionTap method and you can find it in the comments below. I have mentioned where I am tapping the option and what is done below it.
Here's what I have done so far:
import 'package:flutter/material.dart';
import 'package:flutter_app/Constants/constants.dart';
import 'package:flutter_app/Models/question_model.dart';
import 'package:flutter_app/ViewModels/QuestionsVM.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
QuizQuestionViewModel questionViewModel = QuizQuestionViewModel();
QuizQuestionModel _questionModel;
Widget updateWidget;
class SQQuiz extends StatefulWidget {
final QuizQuestionModel quizQuestionModel;
final int quizId;
SQQuiz({Key key, #required this.quizQuestionModel, #required this.quizId})
: super(key: key);
#override
_SQQuizState createState() =>
_SQQuizState(quizQuestionModel: quizQuestionModel, quizId: quizId);
}
class _SQQuizState extends State<SQQuiz> {
final QuizQuestionModel quizQuestionModel;
final int quizId;
_SQQuizState(
{Key key, #required this.quizQuestionModel, #required this.quizId});
#override
Widget build(BuildContext context) {
_questionModel = quizQuestionModel;
updateWidget = QuestionView(
quizQuestionModel: _questionModel,
quizId: quizId,
);
return Scaffold(
appBar: AppBar(
leading: Container(
child: Row(
children: <Widget>[
IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: Icon(Icons.arrow_back),
),
],
),
),
title: Padding(
padding: const EdgeInsets.symmetric(horizontal: 0),
child: Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(
_questionModel.questionDetail.quizName,
style: TextStyle(color: Constants.greyColor, fontSize: 12),
textAlign: TextAlign.left,
),
SizedBox(
width: 14,
),
CircularProgressIndicator(
value: 15,
strokeWidth: 2,
),
],
),
),
),
actions: <Widget>[
Container(
margin: const EdgeInsets.only(right: 10),
child: Center(
child: Container(
child: Text("SCORE ${_questionModel.score}"),
),
),
)
],
),
body: SafeArea(child: updateWidget),
);
}
}
class QuestionView extends StatefulWidget {
final QuizQuestionModel quizQuestionModel;
final int quizId;
QuestionView(
{Key key, #required this.quizQuestionModel, #required this.quizId})
: super(key: key);
#override
_QuestionViewState createState() => _QuestionViewState(
quizQuestionModel: quizQuestionModel,
quizId: quizId,
);
}
class _QuestionViewState extends State<QuestionView> {
final QuizQuestionModel quizQuestionModel;
final int quizId;
_QuestionViewState({#required this.quizQuestionModel, #required this.quizId});
#override
Widget build(BuildContext context) {
QuestionDetail questionDetail = quizQuestionModel.questionDetail;
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(
height: 10,
),
Text(
"Question ${quizQuestionModel.count}/${quizQuestionModel.totalCount}",
style: TextStyle(fontSize: 12),
),
SizedBox(
height: 5,
),
Image(
image: NetworkImage(
questionDetail.pic,
),
fit: BoxFit.cover,
),
Container(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 50),
color: Constants.orangeColor,
child: Text(
questionDetail.title,
style: TextStyle(
color: Colors.white,
fontSize: 16,
),
textAlign: TextAlign.center,
),
),
ListView.builder(
itemBuilder: (context, index) {
Answers answers = questionDetail.answers[index];
return Card(
elevation: 5,
margin:
const EdgeInsets.symmetric(vertical: 10, horizontal: 0),
child: ListTile(
onTap: () { //This is where I am tapping the option
optionTap(
context: context,
sessionId: quizQuestionModel.sessionId,
quizId: quizId,
questionId: questionDetail.questionId,
answerId: answers.id,
hintUsed: false,
fiftyUsed: false,
).then((response) {
setState(() { //Here the updateWidget is updated, which you can see in the body, but it is not rendered
_questionModel = response;
updateWidget = new QuestionView(
quizQuestionModel: response,
quizId: quizId,
); // The new QuestionView with new details
});
});
},
contentPadding: const EdgeInsets.symmetric(vertical: 10),
title: Text(
answers.title,
textAlign: TextAlign.center,
),
),
);
},
itemCount: questionDetail.answers.length,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
),
SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
RaisedButton(
padding: const EdgeInsets.symmetric(horizontal: 50),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
onPressed: () {
print("50-50 Tapped");
},
child: Text(
"50 | 50\n ${quizQuestionModel.fiftyCoin} coins",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
),
),
),
Wrap(
spacing: 3,
children: <Widget>[
Icon(FontAwesomeIcons.coins),
Text("${quizQuestionModel.coins}"),
],
),
RaisedButton(
padding: const EdgeInsets.symmetric(horizontal: 50),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
onPressed: () {
print("Hint Tapped");
},
child: Text(
"HINT\n ${quizQuestionModel.hintUsed} coins",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
),
),
)
],
),
],
)
],
);
}
There are no errors at the moment, can anyone please help me with this? Thanks in advance.
No offence - but I think you have completely misunderstood the concept of state management in flutter.
If you have a stateful widget, the setState() method triggers the build() method again. So setState is a notifier to say: Hey there was an update to our variable, please build again.
Your Stateful Widget is doing that. BUT there are no new updates on variables from that widget, because your variables ARE OUTSIDE of the widget. They won't get updated for your StatefulWidget. Consider to rethink you architecture. For small Apps it is enough to pass the variables in a constructor.
Here are some links to get closer to the Flutter-State-Management-Concept:
https://flutter.dev/docs/get-started/codelab
https://flutter.dev/docs/development/data-and-backend/state-mgmt/options
for adding a method ontap() in my listview with a custom class that I made for it look of a tile
i tried adding ontap(): but don't recognized it says
here is the code
class _MenuCard extends StatelessWidget {
final String headImageAssetPath;
final IconData icon;
final Color iconBackgroundColor;
final String title;
final String subtitle;
final int heartCount;
_MenuCard({
this.headImageAssetPath,
this.icon,
this.iconBackgroundColor,
this.title,
this.subtitle,
this.heartCount,
});
#override
Widget build(BuildContext context) {
return new Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0, bottom: 10.0),
child: new Card(
elevation: 10.0,
child: new Column(
children: [
new Image.asset(
headImageAssetPath,
width: double.infinity,
height: 100.0,
fit: BoxFit.cover,
),
new Row(
children: [
new Padding(
padding: const EdgeInsets.all(15.0),
child: new Container(
padding: const EdgeInsets.all(10.0),
decoration: new BoxDecoration(
color: iconBackgroundColor,
borderRadius: new BorderRadius.all(const Radius.circular(15.0)),
),
child: new Icon(
icon,
color: Colors.white,
),
),
),
new Expanded(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
new Text(
title,
style: const TextStyle(
fontSize: 25.0,
fontFamily: 'mermaid',
),
),
new Text(
subtitle,
style: const TextStyle(
fontSize: 16.0,
fontFamily: 'bebas-neue',
letterSpacing: 1.0,
color: const Color(0xFFAAAAAA),
),
),
],
),
),
new Container(
width: 2.0,
height: 70.0,
decoration: new BoxDecoration(
gradient: new LinearGradient(
colors: [
Colors.white,
Colors.white,
const Color(0xFFAAAAAA),
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
),
new Padding(
padding: const EdgeInsets.only(left: 15.0, right: 15.0),
child: new Column(
children: [
new Icon(
Icons.favorite_border,
color: Colors.red,
),
new Text(
'$heartCount',
),
],
),
),
],
),
],
),
),
);
}
}
this code is of class that I use to build my listview in the scaffold of the stateless widget.
and here is how I am building my listview after returning scaffold in body:
the code is below
body: new ListView(
children: [
new _MenuCard(
headImageAssetPath: 'images/img.png',
icon: Icons.fastfood,
iconBackgroundColor: Colors.orange,
title: 'il domacca',
subtitle: "78 5TH AVENUE, NEW YORK",
heartCount: 84
),
new _MenuCard(
headImageAssetPath: 'images/img.png',
icon: Icons.local_dining,
iconBackgroundColor: Colors.red,
title: 'Mc Grady',
subtitle: "79 5TH AVENUE, NEW YORK",
heartCount: 84
),
new _MenuCard(
headImageAssetPath: 'images/img.png',
icon: Icons.fastfood,
iconBackgroundColor: Colors.purpleAccent,
title: 'Sugar & Spice',
subtitle: "80 5TH AVENUE, NEW YORK",
heartCount: 84
),
]
),
You can wrap you custom list item widget inside a GestureDetector which has an onTap callback method you can specify.
Example -
class _MenuCard extends StatelessWidget {
final String headImageAssetPath;
final IconData icon;
final Color iconBackgroundColor;
final String title;
final String subtitle;
final int heartCount;
final VoidCallback onTapCallback; //Add this custom onTap method
_MenuCard({
this.headImageAssetPath,
this.icon,
this.iconBackgroundColor,
this.title,
this.subtitle,
this.heartCount,
this.onTapCallback,
});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTapCallback,
child: new Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0, bottom: 10.0),
child: //Rest of your code
),
);
}
}
And inside ListView you can specify your custom onTapCallback.
body: new ListView(
children: [
new _MenuCard(
headImageAssetPath: 'images/img.png',
icon: Icons.fastfood,
iconBackgroundColor: Colors.orange,
title: 'il domacca',
subtitle: "78 5TH AVENUE, NEW YORK",
heartCount: 84,
onTapCallback: () {
// Your onTap code goes here
}
),
// Rest of your code
]
)
Besides onTap, the GestureDetector widget also has a lot of other user event callbacks. You can find out more about them here.
Also, the same functionality can also be achieved with the help of the InkWell widget, you will just need to replace GestureDetector with InkWell and the rest of the code will remain same. Documentation for the widget can be found here.
Hope this helps!