Flipping and Localizing Image Assets

When you support Right-to-Left (RTL) language directions you may find you need to flip or mirror image assets. Asset catalogs have supported directional image assets since Xcode 8 and iOS 10. Unfortunately it doesn’t always seem to work as expected.

Starting with Xcode 11 you can localize images in the asset catalog but that shouldn’t be necessary if you only want to mirror an image. Here’s what works for me.

Directional Image Assets

I have an image in the asset catalog that I’m using to flag a table view cell:

Green triangle image in asset catalog

I pin the image to the top and trailing corner of the table view cell content view:

Table view cell with green chevron in top right corner

In UIKit, I created the layout with stack views with the top stack view constrained to the leading/trailing margins of the table view cell content view. You can do something similar with SwiftUI stack views. Either way when using a RTL language the text direction will automatically switch.

Running on the simulator, we can set a pseudo right-to-left language in the scheme to see the effect:

Right-to-Left pseudolanguage in scheme editor

The system has switched the layout direction but the image now looks a bit odd:

Table view cell shown using pseudo right-to-left language

If you’re building this layout with SwiftUI this is a good time to use Xcode previews and override the layout direction environment:

struct CountryCell_Previews: PreviewProvider {
  static let uk = Country(name: "United Kingdom", capital: "London", 
         continent: "Europe", population: 65000000, visited: true)

  static var previews: some View {
    Group {
      CountryCell(country: uk)
      CountryCell(country: uk)
        .environment(\.layoutDirection, .rightToLeft)
        .previewDisplayName("RTL")
      }
      .previewLayout(.sizeThatFits)
      .padding()
  }
}

Xcode preview of cell using default and right-to-left layout directions

What I want is to flip the image for right-to-left layouts. Asset catalogs got support for directional image assets in Xcode 8 and iOS 10. Change the default “Fixed” direction to “Left to Right, Mirrors” in the inspector:

Direction set to Left-to-right, mirrors for an image in the asset catalog

The individual images now show as “Left to Right” in the asset catalog:

Left to right images in the asset catalog

Unfortunately, if you try it with a right-to-left layout direction nothing changes. The image is never mirrored which is not what I expected…

Just for Buttons?

I don’t know if it’s always been this way but I went back and found the WWDC demo of this feature. It’s shown in WWDC 2016 Session 232 - What’s New in International User Interfaces. What’s interesting though is that Apple shows it with a button - surely that’s not the problem?

Let’s try it using the image as the background for a UIButton. For comparison, I have some text and the same image in a horizontal stack view below the button, shown here with right-to-left layout:

Flipped image when used with a button.

The system has indeed flipped the button image! I can’t find anything from Apple to say that the asset catalog support for layout direction only works for buttons so I have to assume this is a bug (FB7687697).

Workarounds

One quick fix is to load the trait compatible image from the asset catalog at runtime. For example, in viewDidLoad, assuming flagImageView is an outlet to the image view created in a storyboard:

let image = UIImage(named: "Flag", in: nil, 
           compatibleWith: traitCollection)
flagImageView.image = image
flagImageView.sizeToFit()

Image view mirrored for right-to-left layout

Another workaround is to add image assets for both layout directions. In the asset catalog change direction to “Both”:

Direction “Both” in asset catalog

We then need to flip the images and add the right-to-left variations to the asset catalog:

Additional right to left images added to asset catalog

SwiftUI has a workaround that I think I prefer over using the asset catalog. Add a view modifier to the image indicating that it should flip for right to left layouts:

Image("Visited")
.flipsForRightToLeftLayoutDirection(true)

This is much clearer than hiding the behaviour in the asset catalog. Especially when accompanied with an Xcode preview showing the effect:

SwiftUI preview with image flipped

Localizing Images in Xcode 11

One final quick note on a new feature in Xcode 11. If you’re unlucky enough to be dealing with images that contain text no amount of image flipping will do the trick. In those cases, Xcode 11 now makes it possible to localize images directly in the asset catalog:

Localize button for images in asset catalog

Select the languages you need and add the localized images directly to the catalog:

Localized images added to asset catalog

Read More