Проверка наличия пути к ресурсу 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()

Другие вопросы по тегам