Chapters

Hide chapters

Flutter Apprentice

Fourth Edition · Flutter 3.16.9 · Dart 3.2.6 · Android Studio 2023.1.1

Section II: Everything’s a Widget

Section 2: 5 chapters
Show chapters Hide chapters

Section IV: Networking, Persistence & State

Section 4: 6 chapters
Show chapters Hide chapters

5. Scrollable Widgets
Written by Vincent Ngo

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

Building scrollable content is an essential part of UI development. There’s only so much information a user can process at a time, let alone fit on an entire screen in the palm of your hand!

In this chapter, you’ll learn everything you need to know about scrollable widgets. In particular, you’ll learn:

  • How to use ListView.
  • How to nest scroll views.

You’ll continue to build the Yummy app by adding HomeScreen, a new view that enables users to explore different restaurants, food categories, and view friends’ posts.

By the end of this chapter, you’ll be a scrollable widget wizard!

Getting Started

Open the starter project in Android Studio, then run flutter pub get if necessary and run the app.

You’ll see a placeholder for each tab as shown below:

Project Files

There are new files in this starter project to help you out. Before you learn how to create scrollable widgets, take a look at them.

Assets Folder

The assets directory contains all the images that you’ll use to build your app.

Sample Images

  • categories: Contains images for food categories.
  • food: Contains sample food items from a restaurant menu.
  • profile_pics: Contains Kodeco team member pictures.
  • restaurants: Contains restaurant hero images.

New Classes

In the lib directory, you’ll also notice the new api folder, as shown below:

API Folder

The api folder contains a mock service class.

XedtlXevyefa KulcvUTE GobzCihwqJuzpuxi

Introducing ListView

ListView is a very popular Flutter component. It’s a linear scrollable widget that arranges its children linearly and supports horizontal and vertical scrolling.

Introducing Constructors

A ListView has four constructors:

Setting Up the Explore Screen

The first screen you’ll create is the ExploreScreen. It contains three sections:

HogosizjFebcoob XusseoxarmDegqiix TufgTampeob

import 'package:flutter/material.dart';
import '../api/mock_yummy_service.dart';


class ExplorePage extends StatelessWidget {
  // 1
  final mockService = MockYummyService();

  ExplorePage({super.key});

  @override
  Widget build(BuildContext context) {
    // TODO: Add Listview Future Builder
    // 2
    return const Center(
        child: Text('Explore Page Setup',
        style: TextStyle(fontSize: 32.0),),);
  }
}

Updating the Navigation Pages

In lib/home.dart, locate // TODO: Replace with ExplorePage and replace Center below it with the following:

ExplorePage(),
import 'screens/explore_page.dart';

Creating a FutureBuilder

How do you display your UI with an asynchronous task?

// 1
  return FutureBuilder(
    // 2
    future: mockService.getExploreData(),
    // 3
    builder: (context, AsyncSnapshot<ExploreData> snapshot) {
      // 4
      if (snapshot.connectionState == ConnectionState.done) {
        // 5
        final restaurants = snapshot.data?.restaurants ?? [];
        final categories = snapshot.data?.categories ?? [];
        final posts = snapshot.data?.friendPosts ?? [];
        // TODO: Replace this with Restaurant Section
        return const Center(
          child: SizedBox(
            child: Text('Show RestaurantSection'),
          ),
        );
      } else {
        // 6
        return const Center(
          child: CircularProgressIndicator(),
        );
      }
    },
  );

Building Restaurant Section

The first scrollable component you’ll build is RestaurantSection. This is the top section of the ExplorePage. It will be a horizontal list view.

import 'package:flutter/material.dart';

// 1
import '../components/restaurant_landscape_card.dart';
import '../models/restaurant.dart';

class RestaurantSection extends StatelessWidget {
  // 2
  final List<Restaurant> restaurants;

  const RestaurantSection({
    super.key,
    required this.restaurants,
  });

  @override
  Widget build(BuildContext context) {
    // 3
    return Padding(
      padding: const EdgeInsets.all(8.0),
      // 4
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const Padding(
            padding: EdgeInsets.only(left: 16.0, bottom: 8.0),
            // 5
            child: Text(
              'Food near me',
              style: TextStyle(
                fontSize: 24,
                fontWeight: FontWeight.bold,
              ),
            ),
          ),
          // TODO: Add Restaurant List View
          // 6
          Container(
            height: 400,
            // TODO: Add ListView Here
            color: Colors.grey,
          ),
        ],
      ),
    );
  }
}

Adding the Restaurant Section

Open explore_page.dart and add the following import:

import '../components/restaurant_section.dart';
// TODO: Wrap in a ListView
return RestaurantSection(restaurants: restaurants);

// 1
SizedBox(
  height: 230,
  // 2
  child: ListView.builder(
    // 3
    scrollDirection: Axis.horizontal,
    // 4
    itemCount: restaurants.length,
    // 5
    itemBuilder: (context, index) {
      // 6
      return SizedBox(
        width: 300,
        // 7
        child: RestaurantLandscapeCard(
          restaurant: restaurants[index],
        ),
      );
    },
  ),
),
import 'restaurant_landscape_card.dart';

Nested ListViews

There are two approaches to adding the category and post sections: the Column approach and the nested ListView approach. You’ll take a look at each of them now.

Column Approach

You could put the list views in a Column, that arranges items in a vertical layout. So that makes sense right?

Huxzy Xinucv FozzaoravhQicruiv YufwDinjoig RidojivpXilcuor

Nested ListView Approach

In the second approach, you nest multiple list views in a parent list view.

Tufhb WajyoaforwBumjoaw VuxugexvHotteud PutgCohbuog EgkfuyuJade WuyfGuon

Adding a Nested ListView

First, go back to explore_page.dart locate the comment // TODO: Wrap in a ListView and replace it and return RestaurantSection widget with the following:

// 1
return ListView(
  // 2
  shrinkWrap: true,
  // 3
  scrollDirection: Axis.vertical,
  // 4
  children: [
    RestaurantSection(restaurants: restaurants),
    // TODO: Add CategorySection
    Container(
      height: 300,
      color: Colors.green,
    ),
    // TODO: Add PostSection
    Container(
      height: 300,
      color: Colors.orange,
    ),
  ],
);

Building Category Section

The second scrollable component you’ll build is CategorySection. Users will be able to scroll through a list of food categories horizontally.

import 'package:flutter/material.dart';
import '../models/food_category.dart';
import 'category_card.dart';

// 1
class CategorySection extends StatelessWidget {
  final List<FoodCategory> categories;
  const CategorySection({super.key, required this.categories});

  @override
  Widget build(BuildContext context) {
    // 2
    return Padding(
      padding: const EdgeInsets.all(8.0),
      // 3
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // 4
          const Padding(
            padding: EdgeInsets.only(left: 16.0, bottom: 8.0),
            child: Text(
              'Categories',
              style: TextStyle(
                fontSize: 24,
                fontWeight: FontWeight.bold,
              ),
            ),
          ),
          // 5
          SizedBox(
            height: 275,
            child: ListView.builder(
              scrollDirection: Axis.horizontal,
              itemCount: categories.length,
              itemBuilder: (context, index) {
                // 6
                return SizedBox(
                  width: 200,
                  child: CategoryCard(
                    category: categories[index],
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

Adding Category Section

Returning to explore_page.dart, locate // TODO: Add CategorySection and replace it and the Container below it with the following:

CategorySection(categories: categories),
import '../components/category_section.dart';

Building the Post Section

The third scrollable component you’ll build is PostSection. Users will be able to scroll through a list of friend posts vertically.

import 'package:flutter/material.dart';
import '../models/post.dart';

// 1
class PostSection extends StatelessWidget {
  final List<Post> posts;
  const PostSection({
    super.key,
    required this.posts,
  });

  @override
  Widget build(BuildContext context) {
    // 2
    return Padding(
      padding: const EdgeInsets.all(8.0),
      // 3
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const Padding(
            padding: EdgeInsets.only(left: 16.0, bottom: 8.0),
            // 4
            child: Text(
              'Friend\'s Activity',
              style: TextStyle(
                fontSize: 24,
                fontWeight: FontWeight.bold,
              ),
            ),
          ),
          // 5
          // TODO: Add Post List View
        ],
      ),
    );
  }
}
// 1
ListView.separated(
  // 2
  primary: false,
  // 3
  shrinkWrap: true,
  // 4
  scrollDirection: Axis.vertical,
  // 5
  physics: const NeverScrollableScrollPhysics(),
  itemCount: posts.length,
  // 6
  itemBuilder: (context, index) {
    return PostCard(post: posts[index]);
  },
  separatorBuilder: (context, index) {
    // 7
    return const SizedBox(height: 16);
  },
),
import 'post_card.dart';

Adding Post Section

Go back to explore_page.dart and find // TODO: Add PostSection and replace it and Container with the following:

PostSection(posts: posts),
import '../components/post_section.dart';

Other Scrollable Widgets

There are many more scrollable widgets for various use cases. Here are some not covered in this chapter:

Xtigeyh Xmujelb

Key Points

  • ListView and GridView support both horizontal and vertical scroll directions.
  • The primary property lets Flutter know which scroll view is the primary scroll view.
  • physics in a scroll view lets you change the user scroll interaction.
  • Especially in a nested list view, remember to set shrinkWrap to true so you can give the scroll view a fixed height for all the items in the list.
  • Use a FutureBuilder to wait for an asynchronous task to complete.
  • You can nest scrollable widgets. For example, you can place a grid view within a list view. Unleash your wildest imagination!

Where to Go From Here?

At this point, you’ve learned how to create ListViews. They are much easier to use than iOS’s UITableView and Android’s RecyclerView, right? Building scrollable widgets is an important skill you should master!

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a Kodeco Personal Plan.

Unlock now