Different size images in horizontal List view / Grid view with fix height and dynamic width in flutter

Viewed 1082

I want to create a horizontal ListView or GridView with fix height of images but width of image should be dynamic.

Below is the code witch I am trying to do but not able to get expected output. I have also added screenshot of design which illustrate the expected output

With List View

import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';


class ViewPager extends StatefulWidget {
  createState() => _ViewPager();
}

class _ViewPager extends State<ViewPager> {

  static final exercise_image1 = "https://drive.google.com/uc?export=download&id=1eDhXVJrNExRwi85pQGCOAwPYi7X-sA0l";
  static final exercise_image2 = "https://drive.google.com/uc?export=download&id=1ifjpLw2ocBAIbEOIhsTtczf8dWuvexri";


  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        children: [
          _imagesList(images: [exercise_image1, exercise_image2]),
        ],
      ),
    );
  }



  Widget _imagesList({List<String> images}) {

    return Container(
      width: double.maxFinite,
      height: 150,
      color: Colors.red,
      child: ListView(
        scrollDirection: Axis.horizontal,
        children: [
          _imageListItem(imagePath: images.first),
          _imageListItem(imagePath: images.last),
        ],
      ),
    );

  }

  Widget _imageListItem({@required String imagePath}) {

    return CachedNetworkImage(
      width: 200, // I want this to be according to the image width
      imageUrl: imagePath,
      placeholder: (context, url) => Container(
        child: CircularProgressIndicator(),
      ),
      imageBuilder: (context, imageProvider) => Container(
        decoration: BoxDecoration(
          image: DecorationImage(
              image: imageProvider,
              fit: BoxFit.fitHeight
          ),
        ),
      ),
    );

  }

}

enter image description here

With Grid View

Same issue with Grid View, we set height of the grid view but not able to give dynamic width to the image

import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';


class ViewPager extends StatefulWidget {
  createState() => _ViewPager();
}

class _ViewPager extends State<ViewPager> {

  static final exercise_image1 = "https://drive.google.com/uc?export=download&id=1eDhXVJrNExRwi85pQGCOAwPYi7X-sA0l";
  static final exercise_image2 = "https://drive.google.com/uc?export=download&id=1ifjpLw2ocBAIbEOIhsTtczf8dWuvexri";


  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Container(
          height: 200,
          child: _imagesList(images: [exercise_image1, exercise_image2]),
        ),
      ),
    );


  }


  Widget _imagesList({List<String> images}) {

    return GridView.count(
      crossAxisCount: 1,
      scrollDirection: Axis.horizontal,
      children: [
        _imageListItem(imagePath: images[0]),
        _imageListItem(imagePath: images[1]),
      ],
    );

  }

  Widget _imageListItem({@required String imagePath}) {

    return CachedNetworkImage(
      imageUrl: imagePath,
      placeholder: (context, url) => Container(
        child: CircularProgressIndicator(),
      ),
      imageBuilder: (context, imageProvider) => Container(
        decoration: BoxDecoration(
          image: DecorationImage(
              image: imageProvider,
              fit: BoxFit.fitHeight
          ),
        ),
      ),
    );

  }

}
4 Answers

One way to achieve this is like so.

class _MyWidgetState extends State<MyWidget> {
  static final exercise_image1 = "https://drive.google.com/uc?export=download&id=1eDhXVJrNExRwi85pQGCOAwPYi7X-sA0l";
  static final exercise_image2 = "https://drive.google.com/uc?export=download&id=1ifjpLw2ocBAIbEOIhsTtczf8dWuvexri";

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Container(
          height: 200,
          child: _imagesList(images: [exercise_image1, exercise_image2]),
        ),
      ),
    );
  }

  Widget _imagesList({List<String> images}) {
    return ListView(
      scrollDirection: Axis.horizontal,
      children: [
        _imageListItem(imagePath: images[0]),
        _imageListItem(imagePath: images[1]),
      ],
    );
  }

  Widget _imageListItem({@required String imagePath}) {
    return CachedNetworkImage(
      imageUrl: imagePath,
      placeholder: (context, url) => Container(
        child: CircularProgressIndicator(),
      ),
    );
  }
}

Try to use listview like this. It is giving the output you wanted.

     @override
  Widget build(BuildContext context) {
    Widget _imageListItem({@required String imagePath}) {
      return   CachedNetworkImage(
        imageUrl: imagePath,
        placeholder: (context, url) => CircularProgressIndicator(),
        errorWidget: (context, url, error) => Icon(Icons.error),
      );
    }
    Widget horizontalList1 = new Container(
      margin: EdgeInsets.symmetric(vertical: 20.0),
      height: 200.0,
      child:
      ListView(
        scrollDirection: Axis.horizontal,
        children: <Widget>[
          _imageListItem(imagePath: exercise_image1),
          SizedBox(width: 2,),
          _imageListItem(imagePath: exercise_image2),

        ],
      ),
    );
    return new Scaffold(
      body: new Center(
        child: new Container(
          child: ListView(
            scrollDirection: Axis.vertical,
            children: <Widget>[
              horizontalList1,
            ],
          ),
        ),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }}

enter image description here

The thing you are talking about is Aspect Ratio, you want it to be fit on the width.

In the image widget, set fit to BoxFit.fitWidth and the problem will be solved.

Read more about it here.

Try this code:

import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';

class ViewPager extends StatelessWidget {
  const ViewPager({Key key}) : super(key: key);

  static final exerciseImages = [
    "https://drive.google.com/uc?export=download&id=1eDhXVJrNExRwi85pQGCOAwPYi7X-sA0l",
    "https://drive.google.com/uc?export=download&id=1eDhXVJrNExRwi85pQGCOAwPYi7X-sA0l",
    "https://drive.google.com/uc?export=download&id=1eDhXVJrNExRwi85pQGCOAwPYi7X-sA0l",
    "https://drive.google.com/uc?export=download&id=1ifjpLw2ocBAIbEOIhsTtczf8dWuvexri",
    "https://drive.google.com/uc?export=download&id=1ifjpLw2ocBAIbEOIhsTtczf8dWuvexri",
    "https://drive.google.com/uc?export=download&id=1ifjpLw2ocBAIbEOIhsTtczf8dWuvexri",
    "https://drive.google.com/uc?export=download&id=1ifjpLw2ocBAIbEOIhsTtczf8dWuvexri",
    // add more image url here. anything you want.
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Container(
          height: 150,
          padding: EdgeInsets.all(12),
          // shuffled to make it a lot more dynamic. demonstration only
          child: _imagesList(images: exerciseImages..shuffle()),
        ),
      ),
    );
  }

  Widget _imagesList({List<String> images}) {
    return ListView.builder(
      physics: BouncingScrollPhysics(), // just for coolness.
      itemCount: images.length,
      scrollDirection: Axis.horizontal,
      itemBuilder: (context, index) {
        return _imageListItem(imagePath: images[index]); // access each images by their index.
      },
    );
  }

  Widget _imageListItem({@required String imagePath}) {
    return Padding(
      padding: const EdgeInsets.all(4), // add padding so the edges of the image is clearly distinguishable.
      child: CachedNetworkImage(
        imageUrl: imagePath,
        placeholder: (context, url) {
          return Center(
            child: Container(
              height: 32, // properly size the loading indicators.
              width: 32, // properly size the loading indicators.
              child: CircularProgressIndicator(),
            ),
          );
        },
      ),
    );
  }
}

I also improved the structure of the code slightly. Made it more dynamic. The fix is that you don't put size at all in the CachedNetworkImage widget. Just give it a url and placeholder. Your code for the parent container with height: 150 is fine. The cache network image will adapt to that height automatically.

Related