Hammad Tariq
Hammad Tariq

Reputation: 13441

Flutter ListView Item Click Listener

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

Answers (7)

lava
lava

Reputation: 7373

enter image description hereListViewpage.dart

        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;
  }
}

Dartpad or Live Code

Upvotes: 6

phankieuphu
phankieuphu

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

advice
advice

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

Yuchen
Yuchen

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

Evelyn
Evelyn

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

Steve
Steve

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

markt
markt

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

Related Questions