iosswiftuipaddingright-to-left

Left and right padding (not leading and trailing) in SwiftUI


A padding modifier in SwiftUI takes an EdgeInsets, eg

.padding(.leading, 8)

However, there are only leading and trailing EdgeInsets, and not left and right. This presents a problem because not everything in RTL languages should necessarily be reversed from the way it's displayed in LTR languages.

Is there a way to achieve the same or similar effect as the padding modifier, which forces the padding to be on left or right side, regardless of directionality of the language?


Solution

  • Use @Environment(\.layoutDirection) to get the current layout direction (LTR or RTL) and use it to flip .leading and .trailing as needed.

    Here’s a ViewModifier that wraps all that conveniently:

    enum NoFlipEdge {
        case left, right
    }
    
    struct NoFlipPadding: ViewModifier {
        let edge: NoFlipEdge
        let length: CGFloat?
        @Environment(\.layoutDirection) var layoutDirection
        
        private var computedEdge: Edge.Set {
            if layoutDirection == .rightToLeft {
                return edge == .left ? .trailing : .leading
            } else {
                return edge == .left ? .leading : .trailing
            }
        }
        
        func body(content: Content) -> some View {
            content
                .padding(computedEdge, length)
        }
    }
    
    extension View {
        func padding(_ edge: NoFlipEdge, _ length: CGFloat? = nil) -> some View {
            self.modifier(NoFlipPadding(edge: edge, length: length))
        }
    }
    

    Use it like you would the standard padding modifiers:

    Text("Text")
        .padding(.left, 10)