GestureDetector onTap Card - dart

new Expanded(
child: _searchResult.length != 0 || controller.text.isNotEmpty
? new ListView.builder(
itemCount: _searchResult.length,
itemBuilder: (context, int i) {
return new Card(
child: new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Row(children: <Widget>[
//new GestureDetector(),
new Container(
width: 45.0,
height: 45.0,
decoration: new BoxDecoration(
shape: BoxShape.circle,
image: new DecorationImage(
fit: BoxFit.fill,
image: new NetworkImage(
"https://raw.githubusercontent.com/flutter/website/master/_includes/code/layout/lakes/images/lake.jpg")))),
new Text(
" " +
userDetails[returnTicketDetails[i]
["user_id"]]["first_name"] +
" " +
(userDetails[returnTicketDetails[i]
["user_id"]]["last_name"]),
style: const TextStyle(
fontFamily: 'Poppins', fontSize: 20.0)),
]),
new Column(
children: <Widget>[
new Align(
alignment: FractionalOffset.topRight,
child: new FloatingActionButton(
onPressed: () {
groupId = returnTicketDetails[i]["id"];
print(returnTicketDetails[i]["id"]);
print(widget.id);
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new Tickets(groupId,widget.id)));
},
heroTag: null,
backgroundColor: Color(0xFF53DD6C),
child: new Icon(Icons.arrow_forward),
)),
new Padding(padding: new EdgeInsets.all(3.0)),
],
)
]));
},
)
: new ListView.builder(
itemCount: _searchResult.length,
itemBuilder: (context, int i) {
return new Card(
child: new ListTile(
//title: new Text(userDetails[returnTicketDetails[i]["user_id"]]["first_name"]),
),
margin: const EdgeInsets.all(0.0),
);
},
),
),
Hi everyone! As I am building dynamically a Card in a ListView, I was thinking rather than keep the FloatingActionButton in each of them as I already do, to implement a onTap method in each card and trigger something.
In other words, I would like to keep the card as simple as possible without many widget around.
Thank you in advance!

As Card is "a sheet of Material", you probably want to use InkWell, which includes Material highlight and splash effects, based on the closest Material ancestor.
return Card(
child: InkWell(
onTap: () {
// Function is executed on tap.
},
child: ..,
),
);

You should really be wrapping the child in InkWell instead of the Card:
return Card(
child: InkWell(onTap: () {},
child: Text("hello")));
This will make the splash animation appear correctly inside the card rather than outside of it.

Just wrap the Card with GestureDetector as below,
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return new ListView.builder(
itemBuilder: (context, i) {
new GestureDetector(
child: new Card(
....
),
onTap: onCardTapped(i),
);
},
);
}
onCardTapped(int position) {
print('Card $position tapped');
}
}

Related

click on image that image style should change or image should be change in flutter

I have 4 images in 2 columns, when I clicked on one image its style should change like color, shadow should change or that image should be replaced by other image. Once click on that image, other images should remain same. It should work like radio buttons. How to do that? Please help me, thanks in advance.
final img_rowi= Center(child:
new Container(
color: Colors.transparent,
padding: const EdgeInsets.all(5.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(padding: const EdgeInsets.all(3.0),child: Stack(
alignment: Alignment.center,
children: <Widget>[
svgIcon,new GestureDetector(
onTap: (){
setState(() {
pressed = !pressed;
});
},
child:
Container(
child: new Column(
children: <Widget>[
new Container(
child: new Image.asset(
'images/sheep_female.png',
height: 50.0,
fit: BoxFit.cover,
),
),
new Container(
child: new Text('Sheep',style: pressed
? TextStyle(color: const Color(0xFFCDCDCD),fontFamily: 'Montserrat',
)
: TextStyle(color:Colors.black,fontFamily: 'Montserrat',
),),
),
],
),
),
),
],
),),
Padding(padding: const EdgeInsets.all(3.0),child:
Stack(
alignment: Alignment.center,
children: <Widget>[
svgIcon,new GestureDetector(
onTap: (){
setState(() {
pressed1 = !pressed1;
});
},
child:
Container(
child: new Column(
children: <Widget>[
new Container(
child: new Image.asset(
'images/biily_doe.png',
height: 50.0,
fit: BoxFit.cover,
),
),
new Container(
child: new Text('Billy Doe',style: pressed1
? TextStyle(color: const Color(0xFFCDCDCD),fontFamily: 'Montserrat',
)
: TextStyle(color:Colors.black,fontFamily: 'Montserrat',
),),
),
],
),
),
),
],
),),
],
),
),
);
Store initial properties of Image in variables. For example if I want to set initial color of FlutterLogo widget to Colors.blue then declare a state in the class. Then wrap your Image with GestureDetector widget and set onTap property. Now call setState method and change all the variables (properties of Image) inside it.
Below is an example where there is one FlutterLogo widget where I've set initial color of that widget to be Colors.blue and when I tap on it, color of FlutterLogo widget is changed to Colors.green. If I again tap on it and if color is Colors.green then it changes color to Colors.yellow and so on. You can do similar thing with your Image and change it's size, visibility and other properties.
There is also imagePath variable which stores path of initial asset and when user taps on second widget (Image.asset) in Column, value of variable imagePath is changed and build method get called again and image is replaced.
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: MyApp()));
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool visibility;
Color colorOfFlutterLogo = Colors.blue;
String imagePath1 = "assets/initial-path-of-image-1";
String imagePath2 = "assets/initial-path-of-image-2";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.black,
),
body: Column(
children: <Widget>[
GestureDetector(
onTap: () => setState(() {
if (colorOfFlutterLogo == Colors.blue)
colorOfFlutterLogo = Colors.green;
else if (colorOfFlutterLogo == Colors.green)
colorOfFlutterLogo = Colors.yellow;
else if (colorOfFlutterLogo == Colors.yellow)
colorOfFlutterLogo = Colors.blue;
}),
child: FlutterLogo(
size: double.infinity,
colors: colorOfFlutterLogo,
),
),
// Image 1
GestureDetector(
onTap: () => setState(() {
imagePath2 = "assets/new-path-for-image-2";
}),
child: Image.asset(imagePath1),
),
// Image 2
GestureDetector(
onTap: () => setState(() {
imagePath1 = "assets/new-path-for-image-1";
}),
child: Image.asset(imagePath2),
)
],
));
}
}

Get card data object in card Buttontheme bar

Good morning,
I'm new on Flutter.
I need to open a new page from a card after a button press. To open the new page I need the card data object that I use to show the information (data[X]). The button for open the new page is located in ButtonTheme.bar but in this location I don't have my "data[X]" object.
This is my code:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Records Page", style: TextStyle(color: Colors.white)),
iconTheme: new IconThemeData(color: Colors.white),
backgroundColor: Color.fromRGBO(32, 38, 48, 1),
),
drawer: MainDrawer(),
body: new ListView.builder(
//reverse: true,
itemCount: reversedData != null ? reversedData.length : 0,
itemBuilder: (BuildContext ctxt, int index) {
if (reversedData[index].stop != null) {
return Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const ListTile(
leading: Icon(Icons.calendar_today),
title: Text('Last Period'),
//subtitle: Text('Music by Julie Gable. Lyrics by Sidney Stein.'),
),
new Container(
margin: EdgeInsets.symmetric(horizontal: 15),
child: new ListView(
shrinkWrap: true,
children: <Widget>[
new Text(
"Hour: ${reversedData[index].hourType.description}"),
new Text("Job: ${reversedData[index].job.description}"),
new Text(
"Opened at: ${DateFormat.yMd().add_jm().format(DateTime.parse(reversedData[index].start))}"),
new Text(
"Closed at: ${DateFormat.yMd().add_jm().format(DateTime.parse(reversedData[index].stop))}"),
],
),
),
ButtonTheme.bar(
// make buttons use the appropriate styles for cards
child: ButtonBar(
children: <Widget>[
FlatButton(
child: const Text('Modify',
style: TextStyle(
color: Color.fromRGBO(32, 38, 48, 1))),
onPressed: () {
Navigator.push(context, new MaterialPageRoute(builder: (__) => new PeriodEditPage(toChangeData: //my card data? ,)));
},
),
],
),
),
],
),
);
}
}));
}
I simply need to have the specific card data when I'm going to open the new page.
Hope I was clear.
Thank you
The trick is to declare your data in your statefulWidget (or statelessWidget) then use then wherever you want.
You can also create an object data where you'll have all your information instanciate one into your widget then pass it to another screen.
Here's an intro about passing data : https://flutter.dev/docs/cookbook/navigation/passing-data
Finally I found the solution to my problem:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Records Page", style: TextStyle(color: Colors.white)),
iconTheme: new IconThemeData(color: Colors.white),
backgroundColor: Color.fromRGBO(32, 38, 48, 1),
),
drawer: MainDrawer(),
body: new ListView.builder(
//reverse: true,
itemCount: reversedData != null ? reversedData.length : 0,
itemBuilder: (BuildContext ctxt, int index) {
if (reversedData[index].stop != null) {
return Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const ListTile(
leading: Icon(Icons.calendar_today),
title: Text('Last Period'),
//subtitle: Text('Music by Julie Gable. Lyrics by Sidney Stein.'),
),
new Container(
margin: EdgeInsets.symmetric(horizontal: 15),
child: new ListView(
shrinkWrap: true,
children: <Widget>[
new Text(
"Hour: ${reversedData[index].hourType.description}"),
new Text(
"Job: ${reversedData[index].job.description}"),
new Text(
"Opened at: ${DateFormat.yMd().add_jm().format(DateTime.parse(reversedData[index].start))}"),
new Text(
"Closed at: ${DateFormat.yMd().add_jm().format(DateTime.parse(reversedData[index].stop))}"),
],
),
),
ButtonTheme.bar(
// make buttons use the appropriate styles for cards
child: ButtonBar(
children: <Widget>[
FlatButton(
child: const Text('Modify',
style: TextStyle(
color: Color.fromRGBO(32, 38, 48, 1))),
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (__) => new PeriodEditPage(
toChangeData: reversedData[index],
)));
},
),
],
),
),
],
),
);
}
}));
}
My problem was solved thank to this line:
toChangeData: reversedData[index],
This code permit to open every card details with the same object used to populate my card.
I haven't understand properly what happen with the object reference but it works for me.

Adding a button to the bottom of a listview widget in flutter

I currently have a listview operating on the whole of my screen. I would like to have a button in the bottom of the screen, thus splitting it up so the listview doens't fill up the whole of my window.
This is the current code building the class:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('HT scoreboard'),
),
body: _buildBody(context),
);
}
Widget _buildBody(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('Spillere').orderBy("score", descending: true).snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return LinearProgressIndicator();
return _buildList(context, snapshot.data.documents);
},
);
}
Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {
return ListView(
padding: const EdgeInsets.only(top: 10.0),
children: snapshot.map((data) => _buildListItem(context, data)).toList(),
);
}
Widget _buildListItem(BuildContext context, DocumentSnapshot data) {
final record = Record.fromSnapshot(data);
return Padding(
key: ValueKey(record.name),
padding: const EdgeInsets.all(5.0),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(5.0),
),
child: ListTile(
title: Text(record.name + ": " + record.score.toString()),
trailing: new IconButton(icon: new Icon(isAdmin ? Icons.add : null, color: Colors.green),
onPressed: (){
if(isAdmin){
record.reference.updateData({'score': record.score + 1});
}
}
),
),
),
);
change your buildlist function to include a column with the button and listview as children
Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {
return Column(
children:[
Expanded(
child: ListView(
padding: const EdgeInsets.only(top: 10.0),
children: snapshot.map((data) => _buildListItem(context, data)).toList(),
),
),
RaisedButton(
// fill in required params
)
])
}
To prevent the buttons being pushed above the keyboard;
return CustomScrollView(
slivers: <Widget>[
SliverToBoxAdapter(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// list items
],
),
),
SliverFillRemaining(
hasScrollBody: false,
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
RaisedButton()
],
),
)
],
);

Flutter: Future Builder fetch multiple data

I am consulting the news section of my website.
I'm using Future Builder to get the data from the web.
The problem I get is related to the image that I try to show on the screen.
And when there is a lot of news, the data load takes a long time and I do not know if there is a solution for loading faster.
I am consulting the text of the news through a json.
At that moment you get the URL of another JSON where the image is in thumbnail format.
I hope to solve this problem, I appreciate any help.
News.dart - Code
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: searchBar.build(context),
key: _scaffoldKey,
body: new Container(
color: Colors.grey[800],
child: new RefreshIndicator(
child: new ListView(
children: <Widget>[
new FutureBuilder<List<Post>>(
future: fetchPosts(URLWEB),
builder: (context, snapshot) {
if(snapshot.hasData) {
List<Post> posts = snapshot.data;
return new Column(
children: posts.map((post2) => new Column(
children: <Widget>[
new Card(
margin: new EdgeInsets.symmetric(vertical: 20.0, horizontal: 20.0),
color: Colors.white,
child: new GestureDetector(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new FutureBuilder(
future: fetchPostsIMG(post2.imagen),
builder: (context, AsyncSnapshot<PostImg> snapshot2){
return new Container(
height: 200.0,
decoration: new BoxDecoration(
image: new DecorationImage(
image: CachedNetworkImageProvider(snapshot2.data.imagen == null ? new AssetImage('images/logotipo.png') : snapshot2.data.imagen),
fit: BoxFit.fitWidth
)
),
width: MediaQuery.of(context).size.width,
);
},
),
new ListTile(
title: new Text(post2.titulo.replaceAll("‘", "").replaceAll(
"’", "").replaceAll("–", "")
.replaceAll("…", "").replaceAll(
"”", "")
.replaceAll("“", ""),
style: new TextStyle(
color: Colors.black,
fontSize: 18.0,
fontWeight: FontWeight.bold),),
subtitle: new HtmlView(data: post2.informacion),
dense: true,
)
],
),
onTap: () {
//Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context)=> new WebView(url: post2.urlweb, titulo: titulo)));
},
)
)
],
)).toList(),
);
}
else if(snapshot.hasError)
{
return new Container();
}
return new Center(
child: new Column(
children: <Widget>[
new Padding(padding: new EdgeInsets.all(50.0)),
new CircularProgressIndicator(),
],
),
);
},
),
],
),
onRefresh: _autoRefresh
),
),
);
}
}
It's because you are trying to access imagen on null object. You can do hasData check like below
CachedNetworkImageProvider(snapshot2.hasData ? snapshot2.data.imagen : new AssetImage('images/logotipo.png')),

How do I shrink the child view like in the GridView

Does any one know how to accomplish the shrinking of the child view in Flutter as show here in the first picture. I used a gridView which does the job very well.
On the second picture I used a row, I tried it with Container and Constrains but it didn't worked out very well. ;D
return new GridView.count(
crossAxisCount: 3,
padding: const EdgeInsets.all(16.0),
mainAxisSpacing: 4.0,
shrinkWrap: true,
crossAxisSpacing: 4.0,
children: widget.foodItems.map((FoodViewModel food){
return new FoodTile(
name: food.name,
icon: food.icon
, onPressed: (bool state) {
food.isSelected = state;
widget?.onFoodItemTaped(food, state);
},
);
}).toList(),
);
Here the row-code without any constrains
return new SingleChildScrollView(
child: new Container(
margin: const EdgeInsets.all(16.0),
child:new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new Container(
padding: const EdgeInsets.all(2.0),
child: new FoodTile(name: "Tile one", onPressed:(bool state){}),
),
new Container(
padding: const EdgeInsets.all(2.0),
child: new FoodTile(name: "Tile two", onPressed:(bool state){}),
),
new Container(
padding: const EdgeInsets.all(2.0),
child: new FoodTile(name: "Tile three", onPressed:(bool state){}),
)
],
)
));
Complete source code to the tile
You should wrap the instances of FoodTile in a Flexible or Expanded so that the Row will apply a flexible layout model to them and space them evenly.
Just if someone is wondering how the end result looks. I'm still a bit unhappy with the "LayoutBuilder-Solution" but it works for me right know.
return new SingleChildScrollView(
child: new Container(
margin: const EdgeInsets.all(16.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Expanded(child: new LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints){
return new Container(
constraints: new BoxConstraints.tightFor(width: constraints.maxWidth, height: constraints.maxWidth),
padding: const EdgeInsets.all(2.0),
child: new FoodTile(name:"hallo",onPressed: (bool state){}),
);
})),
new Expanded(child: new LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints){
return new Container(
constraints: new BoxConstraints.tightFor(width: constraints.maxWidth, height: constraints.maxWidth),
padding: const EdgeInsets.all(2.0),
child: new FoodTile(name:"hallo 2",onPressed: (bool state){}),
);
})),
new Expanded(child: new LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints){
return new Container(
constraints: new BoxConstraints.tightFor(width: constraints.maxWidth, height: constraints.maxWidth),
padding: const EdgeInsets.all(2.0),
child: new FoodTile(name:"hallo 3",onPressed: (bool state){}),
);
})),
],
),

Resources