How to check if image assets exist then use it as circle avatar or write first letter of name in circle avatar

2.2k views Asked by At

i have some images in my assets folder. I just want to check whether the user entered name is matching with image or not. if it is matching then I want to use that image in circle avatar or else use the first letter of the name in circle avatar.

My Logic

I am trying to load image via rootBundle.loadString(). If the image or path does not exist then it will throw an exception. that's how I know that I need to use the first letter of the name.

What I have tried so far

My first approach was just to check whether the path exists or not. for that, I have used the following instruction. but It was giving me always false. I could not find a proper reason for that.

io.File(syncPath).exists();

therefore, I am using rootBundle.loadString() to catch exception.

I have searched on the internet but I could not my found a solution related to my problem (probably because of my bad searching skill)

I have also tried following solutions, I have tried wrapping FutureBuilder on Card() like

  child: FutureBuilder<String>(
    future: rootBundle.loadString(imagePath),
    builder: (BuildContext context,snapshot) {
           if (snapshot.hasData){
           return Card(...)// card and avatar with image
         } else {
         return Card(...)// card and avatar with first letter of name
        }
}

but still, I can not grab exception.

here is my code.

class ItemCardListTile extends StatefulWidget {
  final bool tobuy;
  final String name;
  const ItemCardListTile({
    Key? key,
    required this.tobuy,
    required this.name,
  }) : super(key: key);

  @override
  _ItemCardListTileState createState() => _ItemCardListTileState();
}

class _ItemCardListTileState extends State<ItemCardListTile> {
  final log = logger(ItemCardListTile);

  String assetsPath = 'assets/images/';

  String imageExt = '.png';

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    final String firstLettter = widget.name[0];
    AssetImage? imageAssets;
    String imagePath = '$assetsPath${widget.name.toLowerCase()}$imageExt';

    Future<AssetImage?> checkImageExist(String imagePath) async {
      try {
        await rootBundle.loadString(imagePath);
        imageAssets = AssetImage(imagePath);
      } catch (e) {
        print(e.toString());
        return null;
      }
    }

    return Card(
      child: widget.tobuy
          ? ListTile(
              leading: (checkImageExist(imagePath) == null)
                  ? CircleAvatar(
                      // backgroundImage: imageAssets,
                      child: Text(firstLettter),
                    )
                  : CircleAvatar(backgroundImage: imageAssets),
              title: Text(widget.name),
            )
          : const SizedBox(),
    );
  }
}

Please help me to solve my issue. thank you very much in advance.

updated my code as per the comment of @PeterKoltai Now I am getting FormatException: Unexpected extension byte (at offset 0) . my image path is correct. I can display a circle avatar image using AssestImage().

 Widget build(BuildContext context) {
    final String firstLettter = widget.name[0];
    final String _imagePath = 'assets/images/broccoli.png';

    Future checkImageExist(String imagePath) async {
      try {
        return await rootBundle.loadString(imagePath);
      } catch (e) {
        print(e.toString());
        return null;
      }
    }

    return FutureBuilder(
      future: checkImageExist(_imagePath),
      builder: (BuildContext context, snapshot) {
        if (snapshot.hasError != null) {
          return Card(
            child: widget.tobuy
                ? ListTile(
                    leading:CircleAvatar(
                      child: Text(firstLettter),
                    ),
                    title: Text(widget.name),
                  )
                : const SizedBox(),
          );
        } else
          return Container();
      },
    );
  }
1

There are 1 answers

0
vivek patel On

So finally little help from everybody I solved the issue. now I can catch all the errors. this is my final code.

class ItemCardListTile extends StatelessWidget {
  final bool tobuy;
  final String name;
  ItemCardListTile({
    Key? key,
    required this.tobuy,
    required this.name,
  }) : super(key: key);

  final log = logger(ItemCardListTile);
  String assetsPath = 'assets/images/';
  String imageExt = '.png';

  @override
  Widget build(BuildContext context) {
    final String firstLettter = name[0];
    final String imagePath = '$assetsPath${name.toLowerCase()}$imageExt';
    Future<AssetImage?> checkImageExist(String imagePath) async {
      try {
        await rootBundle.load(imagePath); //  return always null so
        return AssetImage(imagePath); // I have added AssetImage
      } catch (e) {
        print(e.toString());
        return null;
      }
    }

    return FutureBuilder(
      future: checkImageExist(imagePath),
      builder: (BuildContext context, snapshot) {
        return Card(
          child: tobuy
              ? ListTile(
                  leading: CircleAvatar(
                    // here I am checking if image is available then I use it otherwise I write
                    // first letter of the name
                    foregroundImage:
                        (snapshot.data != null) ? AssetImage(imagePath) : null,
                    child: Text(firstLettter),
                  ),
                  title: Text(name),
                )
              : const SizedBox(),
        );
      },
    );
  }
}