Mark
Mark

Reputation: 3859

Is it possible to have a listview maintain its position as images of variable height load in flutter?

Lets say you have a ListView of variable height:

At this point, when one of the network images above your position load up, the entire ListView will be pushed and you will no longer be looking at Item #11, rather somewhere randomly higher up

I considered initiating a new scroll in a callback after each image loads, however, due to network speeds, usually the listview scroll will finish before all the images load. If there are a lot of images, the images could take time to load, so it would be unreasonable to initiate a new scroll each time a new image is loaded, the screen just keeps scrolling forward every few seconds. It becomes dizzying and annoying.

Alternatively, the scrollview could jumpTo a new position as soon as the image loads, but I'm imagining there would be a slight delay between the two events and the user perceive a small "glitch" as the image loads and the listview immediately jumps to offset the image load. Even using a Future.microtask there is a very small perceptible 'glitch' as the image loads and the jumpto fires

It would be most preferable to have the listview expand the content upward somehow, so that the users current scroll position is maintained, as far as they are concerned.

Is it possible to have the ListView keep its position as the images load?

Upvotes: 1

Views: 1060

Answers (4)

Nabin Dhakal
Nabin Dhakal

Reputation: 2202

Try as follows:

enter image description here

 ListView.builder(
            shrinkWrap: true,
            itemCount: images.length,
            itemBuilder: (ctx, i) {
              return Column(children: [
                ButtonItems(i),
                const SizedBox(height: 10),
              ]);
            }));

Button Items class

    class ButtonItems extends StatefulWidget {
  final int i;
  ButtonItems(this.i);
  @override
  _ButtonItems createState() => _ButtonItems();
}

class _ButtonItems extends State<ButtonItems> {
  var images = [
    "https://opengraph.githubassets.com/2ddb0ff05ef9ccfce35abb56e30d9c5068e01d1d10995484cfd07becee9accf7/dartpad/dartpad.github.io",
    null,
    "https://opengraph.githubassets.com/2ddb0ff05ef9ccfce35abb56e30d9c5068e01d1d10995484cfd07becee9accf7/dartpad/dartpad.github.io"
  ];
 
  @override
  Widget build(BuildContext context) {
    print(images[widget.i]);
    return Container(
        height: 50,
        color: Colors.grey,
        child: Row(children: [
          AspectRatio(
            aspectRatio: 3 / 2,
            child: images[widget.i] == null
                ? Container()
                : Image.network(images[widget.i]!, fit: BoxFit.cover),
          ),
          Text("Title " + widget.i.toString()),
        ]));
  }
}

Upvotes: 0

Deep Dave
Deep Dave

Reputation: 157

Images are of variable height

To overcome this, Either we take the image size or aspect ratio of the image while storing the image along with other data.

While retrieving data, along with other text data we will receive the aspect ratio or height for the image.

I would use the same height or ratio and show placeholder image till images are loaded.

CachedNetworkImage(
              imageUrl: countryList[index].flagUrl,
              height: 60, // Set your height according to aspect ratio or fixed height
              width: 60,
              fit: BoxFit.cover,
              placeholder: (_, __) => Container(
                alignment: Alignment.center,
                height: 60,  // Set your height 
                width: 60,
                color: Colors.red.withAlpha(80),
                child: Text(
                  countryList[index].name[0],
                  style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
                ),
              ),
            )

Image must be of specific aspect ratio I believe. You can define height according to aspect ratio.

Upvotes: 0

d1nch8g
d1nch8g

Reputation: 619

Animated container, might help you. It can adjust the height automatically, depending on the height u provide in builder.

Also you can use this answer to determnin image height and width in rnutime.

Upvotes: 0

Christian
Christian

Reputation: 1068

Assuming you have a predefined size for your images, you can wrap the image in a SizedBox(). This way your list will always have the same height and your items won't get pushed around.

EDIT: Since your images are of variable size, I would probably animate to the desired location on every image load.

CachedNetworkImage has a callback

imageBuilder: (context, imageProvider) {
  /// Animate to desired index
  return Image(image: imageProvider);
}

Upvotes: 1

Related Questions