Which layouts and images mirror for right-to-left languages automatically, and what must you handle yourself in custom drawing?
Predict first
Where do cells land in a mirrored flow layout, and which images flip?
import UIKit
final class DS: NSObject, UICollectionViewDataSource {
func collectionView(_ c: UICollectionView, numberOfItemsInSection s: Int) -> Int { 2 }
func collectionView(_ c: UICollectionView, cellForItemAt i: IndexPath) -> UICollectionViewCell { c.dequeueReusableCell(withReuseIdentifier: "c", for: i) }
}
@MainActor func run() {
let v = UIView(); v.semanticContentAttribute = .forceRightToLeft
print("direction raw (0 ltr, 1 rtl):", v.effectiveUserInterfaceLayoutDirection.rawValue,
UIView.userInterfaceLayoutDirection(for: .forceRightToLeft).rawValue,
UIView.userInterfaceLayoutDirection(for: .playback).rawValue,
UIView.userInterfaceLayoutDirection(for: .spatial).rawValue)
let layout = UICollectionViewFlowLayout(); layout.itemSize = CGSize(width: 100, height: 50)
let cv = UICollectionView(frame: CGRect(x: 0, y: 0, width: 320, height: 200), collectionViewLayout: layout)
let ds = DS()
cv.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "c"); cv.dataSource = ds
for attr in [UISemanticContentAttribute.forceLeftToRight, .forceRightToLeft] {
cv.semanticContentAttribute = attr
cv.reloadData(); cv.layoutIfNeeded()
let x = (0..<2).map { layout.layoutAttributesForItem(at: IndexPath(item: $0, section: 0))!.frame.origin.x }
print(attr == .forceRightToLeft ? "rtl" : "ltr", "item x:", x)
}
let chevron = UIImage(systemName: "chevron.right")!, star = UIImage(systemName: "star")!
print("flips: chevron", chevron.flipsForRightToLeftLayoutDirection, "star", star.flipsForRightToLeftLayoutDirection, "after flipped copy:", chevron.imageFlippedForRightToLeftLayoutDirection().flipsForRightToLeftLayoutDirection)
}
MainActor.assumeIsolated { run() }
- direction raw: 1 1 0 0 / ltr item x: [0.0, 110.0] / rtl item x: [220.0, 110.0] / flips: chevron false star false after flipped copy: true
- rtl item x: [0.0, 110.0]
- chevron true star true
Mental model. Reading a book from the other end: the page numbers, the binding and the flow of the story all change. A ruler drawn by hand on the page does not turn itself round.
The first-pass question covered leading and trailing constraints. The remaining gaps are components that mirror themselves and the things that never do. A UICollectionViewFlowLayout lays items out from the reading start: the check puts two 100-point cells in a 320-point collection and gets x = 0 and 110 in left-to-right but x = 220 and 110 when semanticContentAttribute is .forceRightToLeft, with no code of yours. The flow layout reports flipsHorizontallyInOppositeLayoutDirection as false because it handles direction internally; that property is for custom layouts that compute absolute x positions, which must either mirror their own maths or return true so UIKit flips their frames. The same check shows that effectiveUserInterfaceLayoutDirection is 1 for a right-to-left view, and that the semantic attributes .playback and .spatial stay left to right (0): media controls and spatial things such as a clock or timeline deliberately do not mirror.
Images do not flip themselves. A symbol such as chevron.right reports flipsForRightToLeftLayoutDirection == false until you ask for the flipped copy (imageFlippedForRightToLeftLayoutDirection()), which then reports true; for your own asset set “Direction: Both, Mirrors” in the catalog, or use the flip modifier in SwiftUI. Custom drawing, CALayer geometry, gesture translations, hand-computed scroll offsets and animations are plain coordinates and never mirror: read effectiveUserInterfaceLayoutDirection and negate x deltas, swipe directions and progress fills. A paging carousel whose swipe-to-next goes the wrong way, or a progress bar filling from the wrong side, is the usual bug (Q472). Verified here: the collection frames and the direction numbers; the visual result of a full screen flipped, and gesture direction, were not run.
Flow layout mirrors itself; images need the flipped copy or catalog setting.
Common traps
- Hard-coding a swipe or progress direction. It is a coordinate, so it will not follow the language.
- Flipping everything. Media controls and clocks keep their direction.
They might follow up with
- How do I test it quickly? The Right-to-Left pseudolanguage in the scheme, then a real language.
- Does the flow layout need
flipsHorizontally…? No; custom layouts do.
Related questions
- 24.3.1 How do you support right-to-left languages: leading and trailing, semantic content attributes, flipping…
- 24.3.2 How is bidirectional text handled, why should you isolate user-generated strings, and how do different…
- 24.4.1 How do you test internationalisation before translations exist: pseudolanguages, launch arguments, text…
← What happens when text contains characters the font does not have…