Tremmillicious
Tremmillicious

Reputation: 506

Checking if AssetImage asset path exist

How do I load AssetImage or check if it exists? The data is coming from the api, so I cannot list all the file paths as constants.

As an example path maybe be 'assets/images/${card.imageType}.png' where card.inageType is a variable.

...
child: Image(
       height: 60.0,
       image: Utils.getImage('assets/images/card-${card.category}.png'),
       ),
...

For my getImage function, I tried 2 kinds but not working

Method 1: Using File: The existsSync method is always false. Keep in mind the await async cannot work as the Image widget is expecting not a Future

static dynamic getImage(path) {
    File f = File(path);
    return f.existsSync()
        ? FileImage(f)
        : const AssetImage('assets/images/default.png');
  }
}

Method 2: Using try catch: The exceptions is not being caught

  static AssetImage getImage(path) {
    AssetImage image;

    try {
      image = AssetImage(path);
    } catch (e) {
      image = const AssetImage('assets/images/default.png');
    }

    return image;
  }

Upvotes: -2

Views: 2034

Answers (3)

Alain. Jr
Alain. Jr

Reputation: 146

For this, I created an async method to check if the file exists, and load a default value if the file doesn't exists, and in my UI, I use a future builder.. Something like.

  static Future<ImageProvider<Object>> loadImage(
  BuildContext context, String imagePath) async {
try {
  final bundle = DefaultAssetBundle.of(context);
  await bundle.load(imagePath);
  return AssetImage(imagePath);
} catch (e) {
  return const AssetImage("assets/no_image_placeholder.png");
}}

And then in the UI,

  SizedBox(
          height: 100.0,
          width: 160.0,
          child: FutureBuilder(
            future: ProductFallbackErrorImage.loadImage(context,
                "assets/product_images/${productName.toLowerCase()}.jpg"),
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return Container(
                  height: 100.0,
                  width: 160.0,
                  decoration: BoxDecoration(
                    borderRadius: const BorderRadius.only(
                      topLeft: Radius.circular(8.0),
                      topRight: Radius.circular(8.0),
                    ),
                    image: DecorationImage(
                      image: snapshot.data as ImageProvider<Object>,
                      fit: BoxFit.fill,
                    ),
                  ),
                );
              } else if (snapshot.hasError) {
                'snapshot has error with value ${snapshot.error.toString()}'
                    .log();
                return Container(
                  height: 100.0,
                  width: 160.0,
                  decoration: const BoxDecoration(
                    borderRadius: BorderRadius.only(
                      topLeft: Radius.circular(8.0),
                      topRight: Radius.circular(8.0),
                    ),
                    image: DecorationImage(
                      image: AssetImage("assets/no_image_placeholder.png"),
                      fit: BoxFit.fill,
                    ),
                  ),
                );
              } else {
                return const CircularProgressIndicator();
              }
            },
          ),
        ),

The error block will never be executed, since we are handling the level of the catch block, so i guess that can be removed.

Upvotes: 0

Zahid Tekbaş
Zahid Tekbaş

Reputation: 951

You can check if a file exists asynchronously with this code:

import 'dart:io';
File("path/to/file").exists() 

or checking it synchronously:

import 'dart:io';
File("path/to/file").existsSync()

Update:

isPathExists() function is called from initState.

AssetBundle is used for to obtain asset inside asset folder. You can insert anything to menubanner.png if it exists, the image will be assigned to variable and if it does not, an exception throws.


  late Image image;
  isPathExists() async {
    try {
      var assetbundle = DefaultAssetBundle.of(context);
      ByteData res = await assetbundle.load('assets/images/menubanner.png');
      var list = Uint8List.sublistView(res);
      setState(() {
        image = Image.memory(list);
      });
    } catch (exception) {
      print(exception);
    }
  }

Upvotes: 0

Mohamed Alsaid
Mohamed Alsaid

Reputation: 960

You can use something like this to check if an asset exists:

// example: 'assets/check_green.png' 
Future<bool> checkIfAssetExists(String fullAssetPath) async {
  final Uint8List encoded = Utf8Codec()
      .encoder
      .convert(Uri(path: Uri.encodeFull(fullAssetPath)).path);
  // returns null if an asset is not found
  final ByteData? asset = await ServicesBinding.instance!.defaultBinaryMessenger
      .send('flutter/assets', encoded.buffer.asByteData());
  return asset != null;
}

You can run this in your initState and then use AssetImage confidently.

As for the exception not being caught, it probably means than an Error was throw which is different from Exceptions

Upvotes: 0

Related Questions