Popular Searches
Popular Course Categories
Popular Courses

Creating scrollable lists

Creating scrollable lists

Flutter Lists & Collections

Creating Scrollable Lists in Flutter – Detailed Notes

Scrollable lists are an important part of Flutter application development. They allow users to move through content that is larger than the available screen area. Flutter provides widgets such as ListView, ListView.builder, ListView.separated, SingleChildScrollView, and CustomScrollView for different scrolling requirements.

1. What is a Scrollable List?

A scrollable list is a user interface containing multiple items that can be moved vertically or horizontally when all items cannot fit within the available screen space.

For example, an application may display:

  • Student records
  • Product lists
  • Contact lists
  • Chat messages
  • Notifications
  • News articles
  • Shopping cart items
  • Settings options
  • API-generated data

2. Why Are Scrollable Lists Important?

Mobile screens have limited space. If an application has more content than can fit on the screen, scrolling provides access to the remaining content without making the interface excessively crowded.

  • Displays large amounts of content.
  • Improves mobile usability.
  • Supports vertical and horizontal scrolling.
  • Can efficiently display dynamic data.
  • Supports user interaction with individual items.
  • Can work with locally stored or API-generated data.

3. Flutter Widgets Used for Scrolling

WidgetPurpose
ListViewDisplays a scrollable linear list of widgets.
ListView.builderCreates list items on demand and is suitable for large or dynamic lists.
ListView.separatedCreates list items with separators between them.
SingleChildScrollViewMakes a single child scrollable.
CustomScrollViewCreates advanced scrolling layouts using slivers.
GridViewCreates a scrollable two-dimensional grid.
PageViewDisplays page-sized children that can be swiped between.

4. Basic ListView

ListView is the most commonly used scrolling widget for linear lists. By default, it scrolls vertically.

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

Flutter's default ListView constructor accepts an explicit list of children and is appropriate for small lists. ([Flutter API](https://api.flutter.dev/flutter/widgets/ListView-class.html))

5. Complete Basic Scrollable List 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('Scrollable List'),
        ),
        body: ListView(
          children: const [
            ListTile(
              leading: Icon(Icons.person),
              title: Text('Rahul Sharma'),
              subtitle: Text('Flutter Developer'),
            ),
            ListTile(
              leading: Icon(Icons.person),
              title: Text('Priya Singh'),
              subtitle: Text('UI Designer'),
            ),
            ListTile(
              leading: Icon(Icons.person),
              title: Text('Amit Kumar'),
              subtitle: Text('Backend Developer'),
            ),
            ListTile(
              leading: Icon(Icons.person),
              title: Text('Neha Verma'),
              subtitle: Text('Software Engineer'),
            ),
          ],
        ),
      ),
    );
  }
}

6. ListView with ListTile

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

ListView(
  children: const [
    ListTile(
      leading: Icon(Icons.home),
      title: Text('Home'),
      subtitle: Text('Go to home page'),
      trailing: Icon(Icons.arrow_forward_ios),
    ),
    ListTile(
      leading: Icon(Icons.person),
      title: Text('Profile'),
      subtitle: Text('View your profile'),
      trailing: Icon(Icons.arrow_forward_ios),
    ),
    ListTile(
      leading: Icon(Icons.settings),
      title: Text('Settings'),
      subtitle: Text('Application settings'),
      trailing: Icon(Icons.arrow_forward_ios),
    ),
  ],
)

7. ListView.builder

ListView.builder is designed for dynamically generated lists. Its builder callback creates children on demand, making it suitable for large or potentially infinite lists. ([Flutter API](https://api.flutter.dev/flutter/widgets/ListView-class.html))

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

Important Properties

  • itemCount – Specifies the number of items.
  • itemBuilder – Creates each list item.
  • scrollDirection – Specifies vertical or horizontal scrolling.
  • controller – Controls the scroll position.
  • physics – Controls scrolling behavior.
  • padding – Adds spacing around the list.
  • shrinkWrap – Allows the scroll view to size itself around its contents when required.
  • itemExtent – Gives children a fixed extent in the scrolling direction.
  • prototypeItem – Uses another widget as the prototype for child extent.

8. Creating a Scrollable List from a Dart List

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

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

9. Understanding itemCount

The itemCount property tells Flutter how many items the builder should represent.

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

If the list contains six elements, students.length is six and the valid indexes are 0 through 5.

10. Understanding itemBuilder

The itemBuilder callback receives the current BuildContext and item index. It returns the widget that should be displayed at that position.

itemBuilder: (context, index) {
  return ListTile(
    title: Text('Student ${index + 1}'),
  );
}

11. Vertical Scrolling

Vertical scrolling is the default behavior of ListView.

ListView.builder(
  scrollDirection: Axis.vertical,
  itemCount: 30,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text('Vertical Item ${index + 1}'),
    );
  },
)

12. Horizontal Scrolling

You can create a horizontally scrollable list by setting scrollDirection to Axis.horizontal.

ListView.builder(
  scrollDirection: Axis.horizontal,
  itemCount: 10,
  itemBuilder: (context, index) {
    return Container(
      width: 150,
      margin: const EdgeInsets.all(8),
      color: Colors.blue,
      child: Center(
        child: Text(
          'Item ${index + 1}',
          style: const TextStyle(
            color: Colors.white,
          ),
        ),
      ),
    );
  },
)

13. Horizontal Category List

Horizontal scrolling lists are commonly used for product categories, filters, tabs, or featured content.

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

ListView.builder(
  scrollDirection: Axis.horizontal,
  itemCount: categories.length,
  itemBuilder: (context, index) {
    return Container(
      width: 130,
      margin: const EdgeInsets.symmetric(
        horizontal: 6,
        vertical: 10,
      ),
      child: Card(
        child: Center(
          child: Text(categories[index]),
        ),
      ),
    );
  },
)

14. ListView.separated

ListView.separated allows you to create list items and separators separately.

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

This is useful when you need dividers or custom spacing between list items. ([Flutter API](https://api.flutter.dev/flutter/widgets/ListView-class.html))

15. Adding Padding to a Scrollable List

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

16. Scrolling Cards

ListView.builder(
  padding: const EdgeInsets.all(12),
  itemCount: 10,
  itemBuilder: (context, index) {
    return Card(
      elevation: 3,
      margin: const EdgeInsets.only(bottom: 12),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Product ${index + 1}',
              style: const TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 8),
            const Text('Product description goes here.'),
          ],
        ),
      ),
    );
  },
)

17. Scrolling a List of Products

class Product {
  final String name;
  final double price;

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

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

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}'),
    );
  },
)

18. Making a List Scrollable with SingleChildScrollView

SingleChildScrollView makes a single child scrollable. It is useful when the content is a single column or row that may exceed the available viewport.

SingleChildScrollView(
  child: Column(
    children: [
      Container(
        height: 300,
        color: Colors.blue,
        child: const Center(
          child: Text('Section 1'),
        ),
      ),
      Container(
        height: 300,
        color: Colors.green,
        child: const Center(
          child: Text('Section 2'),
        ),
      ),
      Container(
        height: 300,
        color: Colors.orange,
        child: const Center(
          child: Text('Section 3'),
        ),
      ),
    ],
  ),
)

19. ListView vs SingleChildScrollView

FeatureListViewSingleChildScrollView
PurposeScrollable collection of itemsScrollable single child
Large dynamic listsExcellent with builderUsually not the preferred approach
Lazy item creationSupported by builderNot its main purpose
Typical usageLists, feeds, menusLong forms or combined content
Multiple dynamic itemsRecommendedCan become inefficient for large content

20. ScrollController

A ScrollController can be used to control and observe a scrollable widget's position.

final ScrollController controller = ScrollController();

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

21. Scrolling to a Specific Position

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

The example above animates the list back toward the beginning.

22. Detecting Scroll Position

final ScrollController controller = ScrollController();

@override
void initState() {
  super.initState();

  controller.addListener(() {
    print(controller.offset);
  });
}

@override
void dispose() {
  controller.dispose();
  super.dispose();
}

Always dispose of a ScrollController when the State object that owns it is removed.

23. reverse Property

The reverse property reverses the scroll direction. This can be useful for interfaces such as chat screens.

ListView.builder(
  reverse: true,
  itemCount: messages.length,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text(messages[index]),
    );
  },
)

24. Scroll Physics

The physics property controls how a scrollable responds to user input.

ListView.builder(
  physics: const BouncingScrollPhysics(),
  itemCount: 30,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text('Item ${index + 1}'),
    );
  },
)

Disable Scrolling

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

25. shrinkWrap

shrinkWrap tells the scroll view to determine its extent from the contents along the scrolling direction. It can be useful when a ListView is placed inside another layout that requires the list to size itself to its children.

Column(
  children: [
    const Text('Students'),
    ListView.builder(
      shrinkWrap: true,
      physics: const NeverScrollableScrollPhysics(),
      itemCount: students.length,
      itemBuilder: (context, index) {
        return ListTile(
          title: Text(students[index]),
        );
      },
    ),
  ],
)

Use shrinkWrap: true only when required because sizing a scrollable based on its contents can require additional layout work.

26. itemExtent

If list items have a fixed size in the scrolling direction, itemExtent can provide that information to Flutter and may improve scrolling/layout efficiency. Flutter's documentation notes that specifying itemExtent or prototypeItem can save work because the scrolling system knows the child extent in advance. ([Flutter API](https://api.flutter.dev/flutter/widgets/ListView-class.html))

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

27. prototypeItem

prototypeItem can be used when the list items have the same extent as a representative widget.

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

itemExtent and prototypeItem cannot be specified together. ([Flutter API](https://api.flutter.dev/flutter/widgets/ListView-class.html))

28. Empty Scrollable List

An application should provide a meaningful empty state instead of displaying a blank screen.

Widget build(BuildContext context) {
  if (students.isEmpty) {
    return const Center(
      child: Text('No students found'),
    );
  }

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

29. Scrollable List with Add and Delete

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

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

class _StudentPageState extends State {
  final List students = [
    'Rahul',
    'Priya',
    'Amit',
  ];

  void addStudent() {
    setState(() {
      students.add('Student ${students.length + 1}');
    });
  }

  void deleteStudent(int index) {
    setState(() {
      students.removeAt(index);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Students'),
      ),
      body: ListView.builder(
        itemCount: students.length,
        itemBuilder: (context, index) {
          return ListTile(
            leading: const Icon(Icons.person),
            title: Text(students[index]),
            trailing: IconButton(
              icon: const Icon(Icons.delete),
              onPressed: () {
                deleteStudent(index);
              },
            ),
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: addStudent,
        child: const Icon(Icons.add),
      ),
    );
  }
}

30. Swipe-to-Delete Scrollable List

The Dismissible widget can be used to remove list items with a swipe gesture.

ListView.builder(
  itemCount: students.length,
  itemBuilder: (context, index) {
    return Dismissible(
      key: ValueKey(students[index]),
      onDismissed: (direction) {
        setState(() {
          students.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(students[index]),
      ),
    );
  },
)

31. Scrollable List with Selection

ListView does not maintain a built-in concept of selected items. Selection can be implemented by maintaining selection state in the application.

int selectedIndex = -1;

ListView.builder(
  itemCount: students.length,
  itemBuilder: (context, index) {
    return ListTile(
      selected: selectedIndex == index,
      title: Text(students[index]),
      onTap: () {
        setState(() {
          selectedIndex = index;
        });
      },
    );
  },
)

32. Scrollable List with Checkboxes

final List tasks = [
  'Learn Dart',
  'Learn Flutter',
  'Build a project',
];

final List completed = [
  false,
  false,
  false,
];

ListView.builder(
  itemCount: tasks.length,
  itemBuilder: (context, index) {
    return CheckboxListTile(
      title: Text(tasks[index]),
      value: completed[index],
      onChanged: (value) {
        setState(() {
          completed[index] = value ?? false;
        });
      },
    );
  },
)

33. Scrollable List with Images

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

34. Scrollable List with Navigation

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

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

35. Nested Scrollable Lists

Nested scrolling requires careful handling of constraints and scroll physics. For example, if a ListView is inside a Column and should occupy the remaining available space, use Expanded.

Column(
  children: [
    const Padding(
      padding: EdgeInsets.all(16),
      child: Text(
        'Student List',
        style: TextStyle(fontSize: 20),
      ),
    ),
    Expanded(
      child: ListView.builder(
        itemCount: students.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(students[index]),
          );
        },
      ),
    ),
  ],
)

36. ListView Inside Column – Common Problem

A common mistake is placing a ListView directly inside a Column without giving it a bounded height.

Incorrect approach:

Column(
  children: [
    const Text('Students'),
    ListView(
      children: const [
        Text('Rahul'),
        Text('Priya'),
      ],
    ),
  ],
)

Better approach:

Column(
  children: [
    const Text('Students'),
    Expanded(
      child: ListView(
        children: const [
          ListTile(title: Text('Rahul')),
          ListTile(title: Text('Priya')),
        ],
      ),
    ),
  ],
)

37. Scrollable List Inside a SingleChildScrollView

Putting independently scrolling ListViews inside a SingleChildScrollView can create unnecessary complexity. If the entire screen should scroll as one unit, consider using one scrollable parent or a sliver-based layout.

For more complex combinations of lists, grids, and app bars, Flutter provides CustomScrollView. A ListView is essentially a CustomScrollView containing a single SliverList. ([Flutter API](https://api.flutter.dev/flutter/widgets/ListView-class.html))

38. CustomScrollView for Advanced Scrolling

CustomScrollView(
  slivers: [
    SliverAppBar(
      expandedHeight: 180,
      pinned: true,
      flexibleSpace: const FlexibleSpaceBar(
        title: Text('Products'),
      ),
    ),
    SliverList(
      delegate: SliverChildBuilderDelegate(
        (context, index) {
          return ListTile(
            title: Text('Product ${index + 1}'),
          );
        },
        childCount: 30,
      ),
    ),
  ],
)

39. Preserving Scroll Position

Flutter scroll views can persist their scroll position during a session using PageStorage. A PageStorageKey can help distinguish different scroll views when needed. ([Flutter API](https://api.flutter.dev/flutter/widgets/ListView-class.html))

ListView.builder(
  key: const PageStorageKey('student-list'),
  itemCount: students.length,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text(students[index]),
    );
  },
)

40. Scrollable Lists and Large Data

When displaying a large collection, avoid manually creating thousands of widgets in a normal ListView. ListView.builder is designed to create children lazily as they become visible.

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

This approach is much more appropriate for large datasets than explicitly creating 10,000 widget objects in a children list.

41. Scrollable List from API Data

Scrollable lists are frequently used to display data retrieved from APIs.

Future> fetchStudents() async {
  await Future.delayed(
    const Duration(seconds: 1),
  );

  return [
    'Rahul',
    'Priya',
    'Amit',
    'Neha',
  ];
}

The resulting data can be displayed with a FutureBuilder and ListView.builder.

FutureBuilder>(
  future: fetchStudents(),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return const Center(
        child: CircularProgressIndicator(),
      );
    }

    if (snapshot.hasError) {
      return Center(
        child: Text('Error: ${snapshot.error}'),
      );
    }

    final students = snapshot.data ?? [];

    if (students.isEmpty) {
      return const Center(
        child: Text('No students found'),
      );
    }

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

42. Loading, Error, Empty and Success States

A production application should consider different data states when displaying a dynamic scrollable list.

  • Loading: Show a progress indicator.
  • Error: Show an error message and retry option.
  • Empty: Show a meaningful empty-state message.
  • Success: Display the scrollable list.

43. ListView Performance Best Practices

  • Use ListView.builder for large or dynamic lists.
  • Provide itemCount whenever the number of items is known.
  • Use const widgets where possible.
  • Avoid unnecessary shrinkWrap: true.
  • Use itemExtent when all items have a known fixed extent.
  • Keep expensive calculations outside the item builder when possible.
  • Use model classes for structured data.
  • Use appropriate keys when list item identity matters.
  • Dispose of manually created ScrollControllers.
  • Use CustomScrollView for complex sliver-based scrolling layouts.

44. Common Mistakes

Mistake 1: Using ListView for a huge static children list

For large dynamic collections, prefer ListView.builder.

Mistake 2: Missing itemCount

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

Mistake 3: Incorrect list index

itemBuilder: (context, index) {
  return Text(students[index]);
}

Make sure the index is valid for the collection.

Mistake 4: Unnecessary shrinkWrap

Do not automatically add shrinkWrap: true to every ListView. Use it only when the layout requires it.

Mistake 5: Forgetting to dispose ScrollController

@override
void dispose() {
  controller.dispose();
  super.dispose();
}

Mistake 6: Putting ListView inside Column without constraints

Use Expanded or another appropriate constraint when the list needs to occupy remaining available space.

45. ListView Constructor Comparison

ConstructorUse CaseLazy Creation
ListView()Small fixed listsNot the main purpose
ListView.builder()Large or dynamic listsYes
ListView.separated()Lists requiring separatorsYes
ListView.custom()Custom child model requirementsDelegate controlled

Flutter documents these as the four main ListView construction options. ([Flutter API](https://api.flutter.dev/flutter/widgets/ListView-class.html))

46. Practical Example – Shopping List

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

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

class _ShoppingPageState extends State {
  final List items = [
    'Milk',
    'Bread',
    'Rice',
    'Apples',
    'Vegetables',
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Shopping List'),
      ),
      body: ListView.separated(
        padding: const EdgeInsets.all(12),
        itemCount: items.length,
        itemBuilder: (context, index) {
          return Card(
            child: ListTile(
              leading: const Icon(Icons.shopping_cart),
              title: Text(items[index]),
              trailing: IconButton(
                icon: const Icon(Icons.delete),
                onPressed: () {
                  setState(() {
                    items.removeAt(index);
                  });
                },
              ),
            ),
          );
        },
        separatorBuilder: (context, index) {
          return const SizedBox(height: 6);
        },
      ),
    );
  }
}

47. Practical Example – Horizontal Product Categories

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

  final List categories = const [
    'All',
    'Electronics',
    'Fashion',
    'Books',
    'Sports',
    'Beauty',
  ];

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: 55,
      child: ListView.builder(
        scrollDirection: Axis.horizontal,
        itemCount: categories.length,
        itemBuilder: (context, index) {
          return Padding(
            padding: const EdgeInsets.symmetric(
              horizontal: 6,
            ),
            child: Chip(
              label: Text(categories[index]),
            ),
          );
        },
      ),
    );
  }
}

48. Practical Example – Chat Messages

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

ListView.builder(
  reverse: true,
  padding: const EdgeInsets.all(12),
  itemCount: messages.length,
  itemBuilder: (context, index) {
    return Align(
      alignment: Alignment.centerRight,
      child: Container(
        margin: const EdgeInsets.only(bottom: 8),
        padding: const EdgeInsets.all(12),
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(12),
          color: Colors.blue,
        ),
        child: Text(
          messages[index],
          style: const TextStyle(
            color: Colors.white,
          ),
        ),
      ),
    );
  },
)

49. When to Use Which Scrollable Widget?

RequirementRecommended Widget
Small vertical listListView
Large dynamic listListView.builder
List with dividersListView.separated
Horizontal listListView or ListView.builder with Axis.horizontal
Single long columnSingleChildScrollView
Two-dimensional scrolling gridGridView
Page-by-page scrollingPageView
List + grid + SliverAppBarCustomScrollView

50. Quick Revision

  • ListView creates a scrollable linear list.
  • Vertical scrolling is the default.
  • Use Axis.horizontal for horizontal lists.
  • ListView.builder creates items on demand.
  • ListView.separated creates items with separators.
  • itemCount defines the number of dynamic items.
  • itemBuilder creates individual items.
  • ScrollController provides control over scroll position.
  • reverse reverses the scroll direction.
  • physics controls scrolling behavior.
  • shrinkWrap allows content-based sizing when required.
  • itemExtent can improve layout efficiency when item size is known.
  • CustomScrollView is useful for advanced sliver-based layouts.

51. Practice Exercises

  1. Create a vertical ListView containing 20 student names.
  2. Create a horizontal list of product categories.
  3. Create a ListView.builder displaying product names and prices.
  4. Create a ListView.separated displaying employee records.
  5. Create a notification list with icons and timestamps.
  6. Create a shopping cart where users can remove items.
  7. Implement swipe-to-delete using Dismissible.
  8. Create a chat screen using a reversed ListView.
  9. Create an empty-state interface for an empty list.
  10. Create a list where tapping an item opens a detail screen.
  11. Create a list with checkboxes for a task-management application.
  12. Create an API-driven list with loading, error, empty, and success states.

52. Key Takeaways

Creating scrollable lists is a fundamental Flutter skill. The basic ListView constructor works well for small fixed collections, while ListView.builder is designed for large or dynamic collections because children are created on demand. ListView.separated is useful when separators are required. Flutter also provides scrolling controls such as ScrollController, scrollDirection, reverse, physics, shrinkWrap, itemExtent, and prototypeItem. For advanced combinations of scrolling content, CustomScrollView and slivers provide additional flexibility. ([Flutter API](https://api.flutter.dev/flutter/widgets/ListView-class.html))

53. Official Flutter Resources

54. Flutter Training Resources

For structured Flutter learning, practical application development, Dart programming, widgets, layouts, and project-based training, visit:

JustAcademy Flutter Training Course

To register for a Flutter course demo:

Register for Flutter Course Demo

whatsapp