Popular Searches
Popular Course Categories
Popular Courses

Flutter ListView

Flutter Lists & Collections

Flutter ListView – Detailed Notes

ListView is one of the most commonly used scrolling widgets in Flutter. It displays widgets in a linear arrangement and allows users to scroll through content vertically or horizontally. Flutter provides different ListView constructors, including the standard ListView, ListView.builder, ListView.separated, and ListView.custom. :contentReference[oaicite:0]{index=0}

1. What is ListView?

A ListView is a scrollable widget used to display a collection of widgets one after another. By default, the list scrolls vertically.

ListView is useful for displaying:

  • Contact lists
  • Product lists
  • Messages and chats
  • Notifications
  • Settings menus
  • News feeds
  • Student or employee records
  • Orders and transactions
  • API-generated data

2. Why Use ListView?

  • It provides built-in scrolling.
  • It can display many widgets in a linear layout.
  • It supports vertical and horizontal scrolling.
  • ListView.builder can create items lazily when they are needed.
  • It works well with dynamic application data.
  • It supports separators, padding, custom scroll behavior, and scroll controllers.

3. Basic ListView Syntax

ListView(
  children: [
    Text('Item 1'),
    Text('Item 2'),
    Text('Item 3'),
  ],
)

The children property contains the widgets that should appear in the list.

4. Simple ListView Example

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: const Text('My List'),
        ),
        body: ListView(
          children: const [
            ListTile(
              leading: Icon(Icons.person),
              title: Text('John'),
              subtitle: Text('Flutter Developer'),
            ),
            ListTile(
              leading: Icon(Icons.person),
              title: Text('Sarah'),
              subtitle: Text('UI Designer'),
            ),
            ListTile(
              leading: Icon(Icons.person),
              title: Text('David'),
              subtitle: Text('Backend Developer'),
            ),
          ],
        ),
      ),
    );
  }
}

5. Understanding ListTile with ListView

ListTile is commonly used inside a ListView to create structured list items.

Important ListTile properties include:

  • leading – Widget displayed at the beginning of the tile.
  • title – Main content of the tile.
  • subtitle – Secondary information.
  • trailing – Widget displayed at the end.
  • onTap – Callback executed when the item is tapped.
  • selected – Indicates whether the item is selected.

6. ListView with Cards

ListView(
  padding: const EdgeInsets.all(12),
  children: [
    Card(
      child: ListTile(
        leading: const Icon(Icons.shopping_bag),
        title: const Text('Laptop'),
        subtitle: const Text('₹55,000'),
        trailing: const Icon(Icons.arrow_forward_ios),
      ),
    ),
    Card(
      child: ListTile(
        leading: const Icon(Icons.phone_android),
        title: const Text('Smartphone'),
        subtitle: const Text('₹25,000'),
        trailing: const Icon(Icons.arrow_forward_ios),
      ),
    ),
  ],
)

7. ListView.builder

ListView.builder is used when list items are generated dynamically. Instead of creating every child immediately, it builds children on demand as they become visible. This makes it suitable for large or potentially infinite lists. :contentReference[oaicite:1]{index=1}

Basic Syntax

ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    return Widget();
  },
)

Important properties:

  • itemCount – Number of items in the list.
  • itemBuilder – Function used to build each item.
  • scrollDirection – Controls vertical or horizontal scrolling.
  • padding – Adds space around the list.
  • controller – Allows programmatic scroll control.
  • physics – Controls scrolling behavior.
  • shrinkWrap – Makes the list size itself based on its contents when needed.
  • itemExtent – Gives list children a fixed extent in the scroll direction.

8. ListView.builder with a List of Strings

final List students = [
  'Rahul',
  'Amit',
  'Priya',
  'Neha',
  'Ankit',
];

ListView.builder(
  itemCount: students.length,
  itemBuilder: (context, index) {
    return ListTile(
      leading: const Icon(Icons.person),
      title: Text(students[index]),
    );
  },
)

Here, index represents the position of the current item. For example, students[0] returns the first student.

9. ListView.builder with List of Maps

final List> products = [
  {
    'name': 'Laptop',
    'price': 55000,
  },
  {
    'name': 'Phone',
    'price': 25000,
  },
  {
    'name': 'Tablet',
    'price': 30000,
  },
];

ListView.builder(
  itemCount: products.length,
  itemBuilder: (context, index) {
    final product = products[index];

    return ListTile(
      title: Text(product['name']),
      subtitle: Text('₹${product['price']}'),
    );
  },
)

10. ListView with Model Classes

For larger applications, creating a model class is generally cleaner than using loosely typed maps.

class Product {
  final String name;
  final double price;

  Product({
    required this.name,
    required this.price,
  });
}

Create product data:

final List products = [
  Product(name: 'Laptop', price: 55000),
  Product(name: 'Phone', price: 25000),
  Product(name: 'Tablet', price: 30000),
];

Display the products:

ListView.builder(
  itemCount: products.length,
  itemBuilder: (context, index) {
    final product = products[index];

    return ListTile(
      leading: const Icon(Icons.shopping_bag),
      title: Text(product.name),
      subtitle: Text('₹${product.price}'),
    );
  },
)

11. Horizontal ListView

By default, ListView scrolls vertically. To create a horizontal list, use scrollDirection: Axis.horizontal.

ListView(
  scrollDirection: Axis.horizontal,
  children: [
    Container(
      width: 150,
      margin: const EdgeInsets.all(8),
      color: Colors.blue,
      child: const Center(
        child: Text('Item 1'),
      ),
    ),
    Container(
      width: 150,
      margin: const EdgeInsets.all(8),
      color: Colors.green,
      child: const Center(
        child: Text('Item 2'),
      ),
    ),
    Container(
      width: 150,
      margin: const EdgeInsets.all(8),
      color: Colors.orange,
      child: const Center(
        child: Text('Item 3'),
      ),
    ),
  ],
)

12. Horizontal ListView.builder

final List categories = [
  'Electronics',
  'Clothing',
  'Shoes',
  'Books',
  'Sports',
];

ListView.builder(
  scrollDirection: Axis.horizontal,
  itemCount: categories.length,
  itemBuilder: (context, index) {
    return Container(
      width: 140,
      margin: const EdgeInsets.all(8),
      child: Card(
        child: Center(
          child: Text(categories[index]),
        ),
      ),
    );
  },
)

13. ListView.separated

ListView.separated is useful when you want a separator between list items. It accepts both an itemBuilder and a separatorBuilder. :contentReference[oaicite:2]{index=2}

final List names = [
  'Rahul',
  'Amit',
  'Priya',
  'Neha',
];

ListView.separated(
  itemCount: names.length,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text(names[index]),
    );
  },
  separatorBuilder: (context, index) {
    return const Divider();
  },
)

14. ListView with Divider

ListView(
  children: const [
    ListTile(title: Text('Home')),
    Divider(),
    ListTile(title: Text('Profile')),
    Divider(),
    ListTile(title: Text('Settings')),
  ],
)

15. Adding Padding to ListView

ListView.builder(
  padding: const EdgeInsets.all(16),
  itemCount: 10,
  itemBuilder: (context, index) {
    return Card(
      margin: const EdgeInsets.only(bottom: 10),
      child: ListTile(
        title: Text('Item ${index + 1}'),
      ),
    );
  },
)

16. ListView with onTap

List items can respond to user interactions using onTap.

ListView.builder(
  itemCount: students.length,
  itemBuilder: (context, index) {
    return ListTile(
      leading: const Icon(Icons.person),
      title: Text(students[index]),
      onTap: () {
        print('Selected: ${students[index]}');
      },
    );
  },
)

17. Navigating to a Detail Screen

A common application pattern is to tap a ListView item and open a detail page.

ListView.builder(
  itemCount: products.length,
  itemBuilder: (context, index) {
    final product = products[index];

    return ListTile(
      title: Text(product.name),
      subtitle: Text('₹${product.price}'),
      onTap: () {
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) {
              return ProductDetails(product: product);
            },
          ),
        );
      },
    );
  },
)

Detail screen:

class ProductDetails extends StatelessWidget {
  final Product product;

  const ProductDetails({
    super.key,
    required this.product,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(product.name),
      ),
      body: Center(
        child: Text(
          'Price: ₹${product.price}',
          style: const TextStyle(fontSize: 24),
        ),
      ),
    );
  }
}

18. Empty List Handling

Applications should handle the situation where there are no items to display. Flutter's ListView documentation recommends conditionally replacing the ListView with another widget for an empty state. :contentReference[oaicite:3]{index=3}

final List items = [];

Widget build(BuildContext context) {
  return items.isEmpty
      ? const Center(
          child: Text('No items available'),
        )
      : ListView.builder(
          itemCount: items.length,
          itemBuilder: (context, index) {
            return ListTile(
              title: Text(items[index]),
            );
          },
        );
}

19. ListView with Icons

ListView(
  children: const [
    ListTile(
      leading: Icon(Icons.home),
      title: Text('Home'),
    ),
    ListTile(
      leading: Icon(Icons.person),
      title: Text('Profile'),
    ),
    ListTile(
      leading: Icon(Icons.notifications),
      title: Text('Notifications'),
    ),
    ListTile(
      leading: Icon(Icons.settings),
      title: Text('Settings'),
    ),
  ],
)

20. ListView with Images

ListView.builder(
  itemCount: 5,
  itemBuilder: (context, index) {
    return ListTile(
      leading: CircleAvatar(
        backgroundImage: NetworkImage(
          'https://example.com/image.jpg',
        ),
      ),
      title: Text('User ${index + 1}'),
    );
  },
)

21. Dynamic User List Example

class User {
  final String name;
  final String email;

  User({
    required this.name,
    required this.email,
  });
}

final List users = [
  User(name: 'Rahul Sharma', email: '[email protected]'),
  User(name: 'Priya Singh', email: '[email protected]'),
  User(name: 'Amit Kumar', email: '[email protected]'),
];

ListView.builder(
  itemCount: users.length,
  itemBuilder: (context, index) {
    final user = users[index];

    return Card(
      child: ListTile(
        leading: const CircleAvatar(
          child: Icon(Icons.person),
        ),
        title: Text(user.name),
        subtitle: Text(user.email),
      ),
    );
  },
)

22. Adding Items Dynamically

ListView can be combined with setState() to update the UI when list data changes.

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State createState() => _MyHomePageState();
}

class _MyHomePageState extends State {
  final List items = [];

  void addItem() {
    setState(() {
      items.add('New Item ${items.length + 1}');
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Dynamic List'),
      ),
      body: ListView.builder(
        itemCount: items.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(items[index]),
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: addItem,
        child: const Icon(Icons.add),
      ),
    );
  }
}

23. Removing Items from ListView

void removeItem(int index) {
  setState(() {
    items.removeAt(index);
  });
}

Use it inside the ListView:

ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text(items[index]),
      trailing: IconButton(
        icon: const Icon(Icons.delete),
        onPressed: () {
          removeItem(index);
        },
      ),
    );
  },
)

24. Swipe to Delete with Dismissible

The Dismissible widget can be used to allow users to swipe a list item away.

ListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    return Dismissible(
      key: ValueKey(items[index]),
      onDismissed: (direction) {
        setState(() {
          items.removeAt(index);
        });
      },
      background: Container(
        color: Colors.red,
        alignment: Alignment.centerLeft,
        padding: const EdgeInsets.only(left: 20),
        child: const Icon(Icons.delete),
      ),
      child: ListTile(
        title: Text(items[index]),
      ),
    );
  },
)

25. ListView and ScrollController

ScrollController allows an application to read and control the scroll position.

final ScrollController controller = ScrollController();

ListView.builder(
  controller: controller,
  itemCount: 50,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text('Item ${index + 1}'),
    );
  },
)

You can programmatically move to the beginning:

controller.animateTo(
  0,
  duration: const Duration(milliseconds: 500),
  curve: Curves.easeInOut,
);

26. ListView scrollDirection

The scrollDirection property determines the direction in which the ListView scrolls.

ListView(
  scrollDirection: Axis.vertical,
  children: const [
    Text('Item 1'),
    Text('Item 2'),
    Text('Item 3'),
  ],
)

Horizontal:

ListView(
  scrollDirection: Axis.horizontal,
  children: const [
    SizedBox(
      width: 150,
      child: Center(child: Text('Item 1')),
    ),
    SizedBox(
      width: 150,
      child: Center(child: Text('Item 2')),
    ),
  ],
)

27. ListView reverse Property

The reverse property reverses the scroll direction.

ListView.builder(
  reverse: true,
  itemCount: 20,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text('Message ${index + 1}'),
    );
  },
)

This technique is commonly useful for chat-style interfaces where newer messages appear toward the bottom.

28. ListView shrinkWrap

shrinkWrap controls whether the scroll view should size itself based on its contents in the scrolling direction. It can be useful when placing a ListView inside another scrollable or a constrained parent, but it should not be enabled unnecessarily because it can add layout work. :contentReference[oaicite:4]{index=4}

Column(
  children: [
    const Text('Categories'),
    ListView.builder(
      shrinkWrap: true,
      physics: const NeverScrollableScrollPhysics(),
      itemCount: 5,
      itemBuilder: (context, index) {
        return ListTile(
          title: Text('Category ${index + 1}'),
        );
      },
    ),
  ],
)

29. ListView Physics

The physics property controls how the list responds to scrolling.

ListView(
  physics: const BouncingScrollPhysics(),
  children: const [
    ListTile(title: Text('Item 1')),
    ListTile(title: Text('Item 2')),
    ListTile(title: Text('Item 3')),
  ],
)

Another example is disabling scrolling:

ListView(
  physics: const NeverScrollableScrollPhysics(),
  children: const [
    Text('Item 1'),
    Text('Item 2'),
  ],
)

30. ListView with itemExtent

itemExtent can be used when list children have a known fixed extent in the scrolling direction. Providing an extent can help Flutter's scrolling machinery perform layout work more efficiently. :contentReference[oaicite:5]{index=5}

ListView.builder(
  itemCount: 100,
  itemExtent: 60,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text('Item ${index + 1}'),
    );
  },
)

31. ListView vs ListView.builder

Feature ListView ListView.builder
Children Explicit widgets Generated using builder
Best for Small lists Large/dynamic lists
Lazy creation Not the main purpose Yes
Dynamic data Possible Very suitable
Large lists Less suitable Recommended

Flutter's documentation recommends the regular constructor for small lists and ListView.builder for large or potentially infinite lists because the builder creates children on demand. :contentReference[oaicite:6]{index=6}

32. ListView vs ListView.separated

Widget Purpose
ListView Display a fixed collection of widgets.
ListView.builder Build dynamic items on demand.
ListView.separated Build items with separators between them.
ListView.custom Provide a custom child model using a delegate.

Flutter currently documents these as the four primary ListView construction options. :contentReference[oaicite:7]{index=7}

33. Complete Product List Example

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class Product {
  final String name;
  final double price;
  final String category;

  Product({
    required this.name,
    required this.price,
    required this.category,
  });
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const ProductPage(),
    );
  }
}

class ProductPage extends StatelessWidget {
  const ProductPage({super.key});

  final List products = const [
    Product(
      name: 'Laptop',
      price: 55000,
      category: 'Electronics',
    ),
    Product(
      name: 'Smartphone',
      price: 25000,
      category: 'Electronics',
    ),
    Product(
      name: 'Headphones',
      price: 3000,
      category: 'Accessories',
    ),
    Product(
      name: 'Keyboard',
      price: 1500,
      category: 'Accessories',
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Products'),
      ),
      body: ListView.builder(
        padding: const EdgeInsets.all(12),
        itemCount: products.length,
        itemBuilder: (context, index) {
          final product = products[index];

          return Card(
            margin: const EdgeInsets.only(bottom: 10),
            child: ListTile(
              leading: const CircleAvatar(
                child: Icon(Icons.shopping_bag),
              ),
              title: Text(product.name),
              subtitle: Text(product.category),
              trailing: Text(
                '₹${product.price.toStringAsFixed(0)}',
              ),
            ),
          );
        },
      ),
    );
  }
}

34. ListView for a Settings Screen

ListView(
  children: [
    ListTile(
      leading: const Icon(Icons.person),
      title: const Text('Account'),
      onTap: () {},
    ),
    ListTile(
      leading: const Icon(Icons.notifications),
      title: const Text('Notifications'),
      onTap: () {},
    ),
    ListTile(
      leading: const Icon(Icons.lock),
      title: const Text('Privacy'),
      onTap: () {},
    ),
    ListTile(
      leading: const Icon(Icons.language),
      title: const Text('Language'),
      onTap: () {},
    ),
    ListTile(
      leading: const Icon(Icons.help),
      title: const Text('Help & Support'),
      onTap: () {},
    ),
  ],
)

35. ListView for a Chat Screen

final List messages = [
  'Hello!',
  'How are you?',
  'I am learning Flutter.',
  'That is great!',
];

ListView.builder(
  reverse: true,
  itemCount: messages.length,
  itemBuilder: (context, index) {
    return ListTile(
      leading: const CircleAvatar(
        child: Icon(Icons.person),
      ),
      title: Text(messages[index]),
    );
  },
)

36. ListView for Notifications

final List> notifications = [
  {
    'title': 'New Message',
    'description': 'You received a new message.',
  },
  {
    'title': 'Order Confirmed',
    'description': 'Your order has been confirmed.',
  },
  {
    'title': 'Payment Successful',
    'description': 'Your payment was successful.',
  },
];

ListView.builder(
  itemCount: notifications.length,
  itemBuilder: (context, index) {
    final notification = notifications[index];

    return ListTile(
      leading: const Icon(Icons.notifications),
      title: Text(notification['title']!),
      subtitle: Text(notification['description']!),
    );
  },
)

37. Performance Considerations

For large datasets, prefer ListView.builder so children can be created on demand instead of explicitly constructing every child at once. Providing itemCount also gives the scroll view information about the number of items. :contentReference[oaicite:8]{index=8}

  • Use ListView.builder for large or dynamic collections.
  • Provide itemCount when the list has a known number of items.
  • Avoid unnecessary widget rebuilding.
  • Use const widgets where appropriate.
  • Avoid unnecessary shrinkWrap: true.
  • Use fixed item extents when appropriate.
  • Keep expensive business logic outside individual list item widgets.
  • For very complex scrolling layouts, consider CustomScrollView.

38. ListView Child Lifecycle

ListView can create visible children lazily and destroy child subtrees when they scroll out of view. When a child becomes visible again, Flutter may recreate its widget subtree. If important state needs to survive scrolling, the application's source-of-truth data should generally live outside the individual list child, or an appropriate keep-alive mechanism can be used. :contentReference[oaicite:9]{index=9}

39. Common Mistakes

Mistake 1: Using a normal ListView for thousands of manually created widgets

For large dynamic data, use ListView.builder.

Mistake 2: Forgetting itemCount

ListView.builder(
  itemCount: products.length,
  itemBuilder: (context, index) {
    return Text(products[index].name);
  },
)

Mistake 3: Unnecessary shrinkWrap

Do not use shrinkWrap: true everywhere. Use it when the layout actually requires the scrollable to size itself around its contents.

Mistake 4: Incorrect index access

itemBuilder: (context, index) {
  return Text(products[index].name);
}

Always make sure the index is valid for the data collection.

Mistake 5: Nesting multiple scrollables without planning their constraints

When combining scrollable widgets, carefully manage scrolling physics, constraints, and whether the inner list should scroll independently.

40. Best Practices

  • Use ListView for small, known collections.
  • Use ListView.builder for dynamic or large collections.
  • Use ListView.separated when separators are required.
  • Use model classes for structured application data.
  • Use const wherever widgets can safely be compile-time constants.
  • Keep data management separate from presentation when applications become larger.
  • Provide meaningful empty states.
  • Use stable keys when list items need identity across updates.
  • Use ScrollController when programmatic scrolling or scroll-position observation is required.
  • Use itemExtent or prototypeItem when appropriate for known item dimensions.

41. When to Use ListView

Requirement Recommended Approach
Small fixed list ListView
Large dynamic list ListView.builder
List with dividers ListView.separated
Horizontal scrolling ListView with Axis.horizontal
Dynamic API data ListView.builder
Complex list/grid/sliver screen CustomScrollView

42. ListView and CustomScrollView

A ListView is essentially a convenient scrolling list built around Flutter's sliver-based scrolling system. When an application needs a combination such as a list, grid, and SliverAppBar in one scrolling area, CustomScrollView can provide more control. :contentReference[oaicite:10]{index=10}

CustomScrollView(
  slivers: [
    SliverList(
      delegate: SliverChildBuilderDelegate(
        (context, index) {
          return ListTile(
            title: Text('Item $index'),
          );
        },
        childCount: 20,
      ),
    ),
  ],
)

43. Practical Mini Project: Contact List

import 'package:flutter/material.dart';

void main() {
  runApp(const ContactApp());
}

class ContactApp extends StatelessWidget {
  const ContactApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const ContactPage(),
    );
  }
}

class ContactPage extends StatelessWidget {
  const ContactPage({super.key});

  final List> contacts = const [
    {
      'name': 'Rahul Sharma',
      'phone': '+91 9876543210',
    },
    {
      'name': 'Priya Singh',
      'phone': '+91 9876543211',
    },
    {
      'name': 'Amit Kumar',
      'phone': '+91 9876543212',
    },
    {
      'name': 'Neha Verma',
      'phone': '+91 9876543213',
    },
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Contacts'),
      ),
      body: ListView.separated(
        itemCount: contacts.length,
        padding: const EdgeInsets.all(10),
        itemBuilder: (context, index) {
          final contact = contacts[index];

          return ListTile(
            leading: CircleAvatar(
              child: Text(
                contact['name']![0],
              ),
            ),
            title: Text(contact['name']!),
            subtitle: Text(contact['phone']!),
            trailing: const Icon(Icons.call),
            onTap: () {
              print('Calling ${contact['name']}');
            },
          );
        },
        separatorBuilder: (context, index) {
          return const Divider();
        },
      ),
    );
  }
}

44. Practice Exercises

  1. Create a ListView displaying 10 student names.
  2. Create a ListView.builder displaying product names and prices.
  3. Create a horizontal category list.
  4. Create a ListView.separated displaying employee records.
  5. Create a notification list with icons.
  6. Create a settings screen using ListView and ListTile.
  7. Create a shopping cart list with delete buttons.
  8. Implement swipe-to-delete using Dismissible.
  9. Create an empty-state UI when the list contains no data.
  10. Create a contact list and open a detail page when an item is tapped.

45. Quick Revision

  • ListView: Creates a scrollable linear list of widgets.
  • ListView.builder: Builds list items on demand.
  • ListView.separated: Builds list items with separators.
  • scrollDirection: Controls vertical or horizontal scrolling.
  • itemCount: Defines the number of dynamic items.
  • itemBuilder: Creates each dynamic list item.
  • padding: Adds space around list content.
  • controller: Controls and observes scrolling.
  • shrinkWrap: Allows the scrollable to size itself around its contents when required.
  • itemExtent: Gives children a known extent in the scrolling direction.
  • reverse: Reverses the scroll direction.
  • physics: Controls scrolling behavior.

46. Key Takeaways

Flutter's ListView is an essential widget for building scrollable interfaces. For small static collections, the normal ListView constructor is simple and convenient. For large or dynamic collections, ListView.builder is generally the appropriate choice because items can be built on demand. ListView.separated is useful when each item needs a separator. Flutter also provides properties such as scrollDirection, controller, physics, shrinkWrap, itemExtent, and prototypeItem for controlling list behavior and layout. :contentReference[oaicite:11]{index=11}

47. Official Flutter Resources

48. Flutter Training Resources

To learn Flutter concepts, widgets, layouts, Dart programming, application development, and practical projects in a structured course, visit:

JustAcademy Flutter Training Course

You can also register for a course demo:

Register for Flutter Course Demo

whatsapp