Flutter SliverList freezes while its loading images

Viewed 301

I have a flutter app. One of my screens is loading lots of images from assets. Sometimes my app is freezing while the images are loading.
Here is my solution: I will put a loading animation, this animation needs to end up after the images are finished rendering but how do I understand all the images are finished rendering?
If you have any other solutions you can share with me :)
here is the Widget tree that loads images, in case if you need to know.

final posts = [
    Post(
      ownerName: "McQueen95",
      avatarPath: "images/mcqueen.jpg",
      imagePaths: ['images/mcqueen.jpg'],
    ),
    Post(
      ownerName: "BugsBunny",
      imagePaths: ['images/Bugs_Bunny.png'],
    ),
    Post(
      ownerName: "Venom",
      imagePaths: ['images/venom.jpg'],
    ),
    Post(
      ownerName: "Po",
      imagePaths: ["images/kungfu_panda.jpg"],
      avatarPath: "images/po.jpg",
    ),
    Post(
      ownerName: "Po",
      imagePaths: ["images/kai.jpg", "images/oogway.jpg", "images/crane.png"],
      avatarPath: "images/po.jpg",
    ),
  ];
@override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: [
        SliverAppBar(
          title: Text("Cossy", style: TextStyle(color: Colors.purple)),
          // elevation: 0,
          pinned: true,
          // expandedHeight: 150.0,
          backgroundColor: backgroundColor,
          systemOverlayStyle: SystemUiOverlayStyle(
            systemNavigationBarColor: backgroundColor,
          ),
        ),
        SliverList(
          delegate: SliverChildBuilderDelegate(
            (context, index) => Padding(
              child: posts[index],
              padding: EdgeInsets.only(
                bottom: (index == posts.length - 1) ? 82 : 12,
              ),
            ),
            childCount: posts.length,
          ),
        )
      ],
    );
  }
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_image_slider/carousel.dart';
class Post extends StatelessWidget {
  Post({
    Key? key,
    this.avatarPath,
    required this.ownerName,
    required this.imagePaths,
  }) : super(key: key);

  final String? avatarPath;
  final String ownerName;
  final List<String> imagePaths;

  @override
  Widget build(BuildContext context) {
    if (imagePaths.length == 0) return Text("no image?");
    return Container(
      decoration: BoxDecoration(
        boxShadow: [
          BoxShadow(
            color: Color(0xFFF2F2F2),
            offset: Offset(0.0, 1.0), //(x,y)
            blurRadius: 6.0,
          ),
        ],
        // color: Color(0xFFF2F2F2),
        color: Colors.deepOrange,
        borderRadius: BorderRadius.all(Radius.circular(10)),
      ),
      child: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(4.0),
            child: Row(
              children: [
                CircleAvatar(
                  child: avatarPath == null ? Icon(Icons.person) : null,
                  backgroundImage:
                      avatarPath == null ? null : AssetImage(avatarPath ?? ""),
                ),
                SizedBox(width: 10),
                Text(ownerName),
                Expanded(
                  child: SizedBox(height: 30),
                ),
                Icon(Icons.settings),
              ],
            ),
          ),
          Carousel(
            indicatorBarColor: Colors.transparent,
            autoScrollDuration: Duration(seconds: 2),
            animationPageDuration: Duration(milliseconds: 500),
            activateIndicatorColor: Colors.grey.shade200,
            animationPageCurve: Curves.bounceInOut,
            indicatorBarHeight: 30,
            indicatorHeight: 10,
            indicatorWidth: 20,
            unActivatedIndicatorColor: Colors.grey.shade700,
            stopAtEnd: true,
            autoScroll: false,
            // widgets
            items: imagePaths
                .map(
                  (imagePath) => Container(
                    decoration: BoxDecoration(color: Colors.black),
                    child: ConstrainedBox(
                      constraints: new BoxConstraints(
                        minHeight: 100,
                        minWidth: 100,
                        // maxHeight: 500,
                        maxHeight: MediaQuery.of(context).size.height * 3 / 2,
                        maxWidth: MediaQuery.of(context).size.width,
                      ),
                      child: FittedBox(
                        fit: BoxFit.scaleDown,
                        alignment: Alignment.center,
                        child: Image(
                          image: AssetImage("$imagePath"),
                        ),
                      ),
                    ),
                  ),
                )
                .toList(),
          ),
          Padding(
            padding: const EdgeInsets.only(
              left: 16,
              right: 16,
              top: 4,
            ),
            child: Row(
              children: [
                TextButton(
                  onPressed: () {
                    print(123);
                  },
                  child: Icon(
                    Icons.star_border_outlined,
                    size: 30,
                    // color: Colors.grey,
                  ),
                ),
                Expanded(
                  child: SizedBox(
                    height: 30,
                  ),
                ),
                Icon(
                  Icons.send_outlined,
                  size: 30,
                  // color: Colors.grey,
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
1 Answers

I solved the bug by giving certain height and width values to the Widget that contains images. Using ConstrainedBox and FittedBox means it will load images first and then measure all items' height and widths and then give height value to ListView. So, that's why the app freezes, measuring ListView's size takes a lot of time.

I changed this:

Container(
  decoration: BoxDecoration(color: Colors.black),
  child: ConstrainedBox(
    constraints: new BoxConstraints(
      minHeight: 100,
      minWidth: 100,
      maxHeight: MediaQuery.of(context).size.height * 3 / 2,
      maxWidth: MediaQuery.of(context).size.width,
    ),
    child: FittedBox(
      fit: BoxFit.scaleDown,
      alignment: Alignment.center,
      child: Image(
        image: AssetImage("$imagePath"),
      ),
    ),
  ),
),

To this:

AspectRatio(
  aspectRatio: 1 / 1,
  child: Container(
    decoration: BoxDecoration(color: Colors.black),
    width: MediaQuery.of(context).size.width,
    alignment: Alignment.center,
    child: ClipRRect(
      // borderRadius: BorderRadius.circular(10),
      child: Image(
        image: AssetImage("${imagePaths[0]}"),
      ),
    ),
  ),
),
Related