How to use renderingMode with AsyncImage in SwiftUI

Viewed 37

I have a button that I want to be an image that can change colors as needed (loading async). To do this, I thought I could do something like this: I thought I could do something like this:

Button(action: { doAction }) {
  AsyncImage(url: URL(string: "test.com")) { image in
    image
      .resizable()
      .aspectRatio(contentMode: .fit)
      .renderingMode(.template)
  }
}

However, when I try to do this, I get a few errors:

"Cannot infer return type for closure with multiple statements"

"Closure containing control flow statement cannot be used with result builder 'TableRowBuilder' "

I'm not sure why these errors show up only when I add the "renderingMode" modifier. Everything works other than adding that. Any idea what I'm doing wrong?

2 Answers

renderingMode is a modifier that's only available on Image. The aspectRatio modifier returns a View so you can't use Image-specific modifiers after it.

The fix is easy, just move aspectRatio one line up, right after resizable.

There are two problems in your code.

  1. You can’t apply image-specific modifiers, like resizable(capInsets:resizingMode:), directly to an AsyncImage. Instead, apply them to the Image instance that your content closure gets when defining the view’s appearance. From Apple developer guide.

    Button(action: { print("Hello") }) {
        AsyncImage(url: URL(string: imageURL)) { phase in
            if let image = phase.image {
                image
                    .resizable()
                    .aspectRatio(contentMode: .fit)
            } else if phase.error != nil {
                Color.red // Indicates an error.
            } else {
                Color.blue // Acts as a placeholder.
            }
        }
        .frame(width: 100, height: 100)
    }
    
    //OR
    
    Button(action: { print("Hello") }) {
        AsyncImage(url: URL(string: imageURL)) { image in
            image
                .resizable()
                .renderingMode(.template)
                .aspectRatio(contentMode: .fit)
        } placeholder: {
            Color.clear
        }
        .frame(width: 100, height: 100) //Size of your button
    }
    
  2. renderingMode modifier needs to be called on Image and you are calling it after aspectRatio(contentMode:). Place it before and you are good to go.

Related