Reputation: 13441
I have a ListView
and I want to navigate to the next page on the item click.
I need an index of the clicked item of my ListView
.
I know this can be done using Controller
. But I couldn't find any example.
Upvotes: 63
Views: 130051
Reputation: 7373
class sta extends StatefulWidget {
const sta({Key? key}) : super(key: key);
@override
State<sta> createState() => _staState();
}
var isShow = false;
var getdata = Diohelper.getdata();
class _staState extends State<sta> {
@override
Widget build(BuildContext context) {
List mwidge = [];
int index = 0;
getdata.forEach((element) {
element.index = index;
mwidge.add(ListTile(
onTap: () {
// on click listner for move to another widget or activity (android native)
Navigator.push(context,
MaterialPageRoute(builder: (context) =>
// here element passing to the detail page element contain index other details
DetailPage(element)));
},
hoverColor: Colors.amber,
title: Text(element.name.toString()),
trailing: element.isShow
? SizedBox(
width: 100,
height: 50,
child: OutlinedButton(
onPressed: () {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text(element.name.toString())));
},
child: Text("Show")),
)
: Container(
width: 100,
),
));
index++;
});
return GestureDetector(
child: Center(
child: ListView(
children: [...mwidge],
),
),
);
}
}
DetailPage.dart
class DetailPage extends StatefulWidget {
productModel model;
DetailPage(this.model, {Key? key}) : super(key: key);
@override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
child: ListView(
children: [
Text("Name:" + widget.model.name.toString()),
Text("Category:" + widget.model.category.toString()),
Text("price:" + widget.model.price.toString())
],
),
));
}
}
FullCode:
import 'package:flutter/material.dart';
void main() =>
runApp(MaterialApp(home: Scaffold(appBar: AppBar(), body: sta())));
class sta extends StatefulWidget {
const sta({Key? key}) : super(key: key);
@override
State<sta> createState() => _staState();
}
var isShow = false;
var getdata = Diohelper.getdata();
class _staState extends State<sta> {
@override
Widget build(BuildContext context) {
List mwidge = [];
int index = 0;
getdata.forEach((element) {
element.index = index;
mwidge.add(ListTile(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => DetailPage(element)));
},
hoverColor: Colors.amber,
title: Text(element.name.toString()),
trailing: element.isShow
? SizedBox(
width: 100,
height: 50,
child: OutlinedButton(
onPressed: () {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text(element.name.toString())));
},
child: Text("Show")),
)
: Container(
width: 100,
),
));
index++;
});
return GestureDetector(
child: Center(
child: ListView(
children: [...mwidge],
),
),
);
}
}
class DetailPage extends StatefulWidget {
productModel model;
DetailPage(this.model, {Key? key}) : super(key: key);
@override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
child: ListView(
children: [
Text("Name:" + widget.model.name.toString()),
Text("Category:" + widget.model.category.toString()),
Text("price:" + widget.model.price.toString())
],
),
));
}
}
class productModel {
String? name;
String? price;
String? category;
bool isShow = false;
int index = 0;
productModel({this.name, this.price, this.category, this.isShow = false});
productModel.fromJson(Map<String, dynamic> json) {
name = json['name'];
price = json['price'];
category = json['category'];
isShow = json['isShow'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
data['price'] = this.price;
data['category'] = this.category;
data['isShow'] = this.isShow;
return data;
}
}
class Diohelper {
static List<productModel> getdata() {
List<productModel> list = [];
list.add(productModel(name: "broast", price: "100", category: "chicken"));
list.add(productModel(name: "mandi", price: "100", category: "chicken"));
list.add(productModel(name: "mandi", price: "100", category: "veg"));
return list;
}
}
Upvotes: 6
Reputation: 196
With listview in you can useing GestureDetetor();
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return new GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RoomDetail()));
},
child: Container(child:(Text("This is content you want")));
Upvotes: 1
Reputation: 5988
If you're using a ListView.builder
, you can use a ListTile
to add an onTap
. This will make sure you have the material ripple effect.
ListView.builder(
itemBuilder: (_, i) {
return ListTile(
title: Text('$i'),
onTap: () {}, // Handle your onTap here.
);
},
)
Upvotes: 53
Reputation: 33036
Another alternative is to use InkWell
. InkWell
includes a nice ripple effect on tap, which GestureDetector
does not have.
https://api.flutter.dev/flutter/material/InkWell-class.html
Use like this:
return Scaffold(
appBar: AppBar(title: Text("Hello World")),
body: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return InkWell(
child: Text(index.toString()),
onTap: () => Scaffold.of(context)
.showSnackBar(SnackBar(content: Text(index.toString()))),
);
},
itemCount: 10)
);
Upvotes: 14
Reputation: 2656
There's an example in the Flutter documentation that's actually this very situation (navigation to next page on item click).
As others have said, use the onTap
on the item in a ListView.builder
. Just thought I'd post the link to the example in case someone else needed a more full explanation.
Send data to a new screen - flutter.io
...
final List<Todo> todos;
...
ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(todos[index].title),
onTap: () {
//Go to the next screen with Navigator.push
},
);
},
);
Upvotes: 20
Reputation: 567
You should use the onPressed method in the item(s) you have in your ListView (or add a GestureDetector) then use Navigator, similar to the snippet below where AboutScreen is the next page you want to go to.
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => AboutScreen()),
);
}
Upvotes: 7
Reputation: 974
When adding the onTap for your GestureRecognizer, (or button), your closure can capture the index passed through in the itemBuilder.
E.g.
body: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
child: Text(index.toString()),
onTap: () => Scaffold
.of(context)
.showSnackBar(SnackBar(content: Text(index.toString()))),
);
},
itemCount: 10));
This code will display a snack bar containing the index of the ListItem that you have tapped.
Once you have the index of the item, you can navigate to a new page using code provided by other answers to this question.
Upvotes: 68