Flutter how to apply LazyLoading or scrollController in ListView.builder that is inside another ListView.builder

Viewed 26

I have a large JSON file (post.json) loaded from local assets folder. I want to know how to apply Lazy Loading or ScrollController (example from Flutter ListView lazy loading) or other better option to load 5000 more of topping list in the second ListView.builder?
Below are the sample Json file, code file and the image.

enter image description here

This is post.json

{
    "Food": [
      {
        "name": "Cake",
        "id": "0001",
        "description": [
          {
            "category": "AAA",
            "Size": "Regular",
            "topping": []
          },
          {
            "category": "BBB",
            "Size": "Small",
            "topping": []
          },
          {
            "category": "CCC",
            "Size": "Medium",
            "topping": [
                {
                    "ingredient": "Chocolate with Sprinkles",
                    "price": "$70"
                },
                {
                    "ingredient": "Maple",
                    "price": "$99"
                },
                {
                    "ingredient": "Blueberry",
                    "price": "$123"
                }, ... // more than 5000 of topping list
            ]
          }
        ]
      },
      {
        "name": "Raised",
        "id": "0002",
        "description": ... // same structure as above
      }
    ]
}

This is the Main file which display List of foods

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

// Load local Json file
Future<Post> getFoodList() => Future.delayed(Duration(seconds: 1), ()  async {
  final getResponse = await rootBundle.loadString('assets/post.json');
  var data = jsonDecode(getResponse);
  return Post.fromJson(data);
});

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Expanded(
            child: FutureBuilder<Post>(
              future: getFoodList(),
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  var getFoodName = snapshot.data!.food;
                  return SingleChildScrollView(
                    child: Wrap(
                      children: [
                        for (final food in getFoodName!)
                          GestureDetector(
                            child: Text(foodName.name.toString()),
                            onTap: () {
                              Navigator.push(context, MaterialPageRoute(builder: (context) => foodDetail(food: food)));
                            },
                          ),
                      ],
                    ),
                  );
                } else {
                  return Text('Loading');
                }
              },
            ),
          ),
        ],
      ),
    );
  }
}

This is Food Detail page. I take some example from Flutter ListView lazy loading but I don't know how to apply it to my second listView.builder which will display more than 5000 of topping list as below:

class FoodDetail extends StatefulWidget {
  final Food food;
  const FoodDetail({super.key, required this.food});

  @override
  State<FoodDetail> createState() => _FoodDetailState();
}

class _FoodDetailState extends State<FoodDetail> {
  late ScrollController controller;
  // This example is taken from Flutter ListView lazy loading
  List<String> items = List.generate(100, (position) => 'Hello $position');

  @override
  void initState() {
    super.initState();
    controller = ScrollController()..addListener(_scrollListener);
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Padding(
            padding: const EdgeInsets.all(8.0),
            child: SingleChildScrollView(
              child: Column(
                children: [
                  // This is the first ListView.build to display category and size under description
                  ListView.builder(
                      itemCount: widget.food.description!.length,
                      itemBuilder: (context, index) {
                        // IF category is AAA || BBB, display the size
                        if (widget.food.description![index].category == "AAA" || widget.food.description![index].category == "BBB") {
                          return Text(widget.food.description![index].size.toString());
                        }
                        // IF category is CCC display the List of Topping (Note: this topping list is more than 5000)
                        else {
                          // This is the second ListView.build to display the topping information
                          // How do I apply ScollController or Lazy Loading to load 5000 list of topping?
                          return ListView.builder(
                              controller: controller,
                              itemCount: widget.food.description![index].topping!.length,
                              itemBuilder: (context, position) {
                                return Column(
                                  children: [
                                    Text(widget.food.description![index].topping![position].ingredient.toString())
                                    Text(widget.food.description![index].topping![position].price.toString())
                                  ],
                                );
                              });
                            }
                          }),
                    ],
                  ),
            )));
  }
  // This example is taken from Flutter ListView lazy loading
  void _scrollListener() {
    if (controller.position.extentAfter < 500) {
      setState(() {
        items.addAll(List.generate(42, (index) => 'Inserted $index'));
      });
    }
  }
}
0 Answers
Related