Проверка наличия пути к ресурсу AssetImage
Как загрузить AssetImage или проверить, существует ли он? Данные поступают из API, поэтому я не могу перечислить все пути к файлам как константы.
В качестве примера путь может быть «assets/images/${card.imageType}.png», где card.inageType — это переменная.
...
child: Image(
height: 60.0,
image: Utils.getImage('assets/images/card-${card.category}.png'),
),
...
Для моей функции getImage я пробовал 2 вида, но не работал
Способ 1 : использование файла: метод existsSync всегда имеет значение false. Имейте в виду, что ожидание async не может работать, так как виджет изображения ожидает не Future
static dynamic getImage(path) {
File f = File(path);
return f.existsSync()
? FileImage(f)
: const AssetImage('assets/images/default.png');
}
}
Способ 2 : Использование try catch: исключения не перехватываются
static AssetImage getImage(path) {
AssetImage image;
try {
image = AssetImage(path);
} catch (e) {
image = const AssetImage('assets/images/default.png');
}
return image;
}
4 ответа
Вы можете проверить, существует ли файл асинхронно с помощью этого кода:
import 'dart:io';
File("path/to/file").exists()
или проверяя его синхронно:
import 'dart:io';
File("path/to/file").existsSync()
Обновлять:
Функция isPathExists() вызывается из initState.
AssetBundle используется для получения актива внутри папки актива. Вы можете вставить что угодно в menubanner.png , если оно существует, изображение будет присвоено переменной, а если нет, будет выдано исключение.
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);
}
}
Для этого я создал асинхронный метод, чтобы проверить, существует ли файл, и загрузить значение по умолчанию, если файл не существует, а в своем пользовательском интерфейсе я использую будущий построитель. Что-то вроде этого.
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");
}}
И затем в пользовательском интерфейсе
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();
}
},
),
),
Блок ошибок никогда не будет выполнен, поскольку мы обрабатываем уровень блока catch, поэтому я думаю, его можно удалить.
Вы можете использовать что-то вроде этого, чтобы проверить, существует ли актив:
// 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;
}
Вы можете запустить это в своем
initState
а затем использовать
AssetImage
уверенно.
Что касается исключения, которое не было поймано, это, вероятно, означает, что
Error
был бросок, который отличается от
Exception
с
Вы не можете использовать Asset Image для изображений, полученных из сети.
Как только вы получите ответ от вашего API. Сохраните URL-адрес изображения в переменной String. Обычно изображения из API хранятся в веб-сервисе.
Когда у вас есть URL-адрес изображения, просто используйте виджет NetworkImage, например:
SizedBox(
width: 75,
height: 75,
child: userImgUrl.isEmpty
? const CircleAvatar(
child: Text('Avatar'))
: CircleAvatar(
radius: 30,
backgroundImage: NetworkImage(
userImgUrl),
backgroundColor: Colors.transparent),)
Представьте, что userImgUrl — это строка, содержащая URL-адрес изображения, которое можно найти в Интернете. Если изображение пустое, просто покажите текст внутри кругового аватара. Если изображение доступно из API, покажите изображение внутри NetworkImage()