Reputation: 506
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
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
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
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 Exception
s
Upvotes: 0