I'm going round in circles with this and would appreciate a fresh viewpoint.

I have the following button, which when tapped must display an image. The image data is fetched from the backend (this part works fine).

IconButton(
  icon: Icon(
    Icons.attach_email_rounded,
    size: 32.0,
  ),
  color: Colors.grey,
  onPressed: () async {
    await showDialog(
      context: context,
      builder: (_) => showAttachment( // <-- error here
          appstate['arg1'],
          appstate['arg2'],
          appstate['arg3]),
    );
  },
)

Function:

Future<Dialog> showAttachment(arg1, arg2, arg3) async {
  Uint8List attachmentData;

  await getAttachment(arg1, arg2, arg3).then(
    (value) => {
      attachmentData = value,
    },
  );
  return Dialog(
    child: Container(
      width: 200,
      height: 200,
      decoration: BoxDecoration(
        image: DecorationImage(
          image: Image.memory(attachmentData).image,
          fit: BoxFit.cover,
        ),
      ),
    ),
  );
}

However, I'm getting the error The return type 'Future<Dialog>' isn't a 'Widget', as required by the closure's context.

Googling around has revealed I need to use FutureBuilder, but I'm not sure how to incorporate that in the above closure code.

I'd appreciate pointers.

Thanks


Solution 1: Alex Meuer

The builder functions for showDialog is synchronous, so in order to use a future we'll have to nest a FutureBuilder into the Dialog and keep the containing function synchronous.

I've adapted your code sample to demonstrate:

Dialog showAttachment(arg1, arg2, arg3) {
    return Dialog(
      child: FutureBuilder<Uint8List>(
        future: getAttachment(arg1, arg2, arg3),
        builder: (context, snapshot) {
          return snapshot.hasData
              ? Container(
                  width: 200,
                  height: 200,
                  decoration: BoxDecoration(
                    image: DecorationImage(
                      image: Image.memory(snapshot.data!).image,
                      fit: BoxFit.cover,
                    ),
                  ),
                )
              : const CircularProgressIndicator();
        },
      ),
    );
  }

It's important to remember that, unless you provide the optional initial data argument for the FutureBuilder, the first time the builder is called, the snapshot won't have data: so we should check that.

Also not shown above is handling errors; which is done in the same way as checking if the snapshot has data.

FutureBuilder Documentation