SwiftUI ScrollView horizontal RTL not working correctly

Viewed 1409

I'm trying to support RTL mode on my ios , which was built using swiftUI every is fine while doing this to change the layour direction :

.environment(\.layoutDirection, .rightToLeft)

Only with horizontal ScrollView , it's not work correctly

when i do this :

 ScrollView(.horizontal) {
            HStack{
                Text("b1")
                Text("b2")
                Text("b3")
            }
        } .environment(\.layoutDirection, .rightToLeft)

Items positions will rotate , but the HSTACK will stay always on the left like the screenshot below : enter image description here

Any solution or hack to make it to the right ?

4 Answers

I find a hack to do this using .flipsForRightToLeftLayoutDirection(true) and .rotation3DEffect

Like that the scrollview will be flipped , than you need to flip each item of HStack to .rotation3DEffect

 ScrollView(.horizontal) {
            HStack{
                Text("b1")
                    .rotation3DEffect(Angle(degrees: 180), axis: (x: CGFloat(0), y: CGFloat(10), z: CGFloat(0)))
                Text("b2")
                 .rotation3DEffect(Angle(degrees: 180), axis: (x: CGFloat(0), y: CGFloat(10), z: CGFloat(0)))
                Text("b3")
                 .rotation3DEffect(Angle(degrees: 180), axis: (x: CGFloat(0), y: CGFloat(10), z: CGFloat(0)))
            }
        }.flipsForRightToLeftLayoutDirection(true)
        .environment(\.layoutDirection, .rightToLeft)

as a hack, you coud start with this:

var body: some View {
    GeometryReader { geom in
        ScrollView(.horizontal) {
            HStack {
                Text("b1")
                Text("b2")
                Text("b3")
            }.environment(\.layoutDirection, .rightToLeft)
             .padding(.leading, geom.size.width - 100) // adjust for the number of items
        }
    }
}

By programatically scrolling (with .scrollTo) to trailing anchor of view in onAppear if layoutDirection is .rightToLeft, you get correct scroll position. Works also if layoutDirection is .leftToRight

struct ScrollViewRTL<Content: View>: View {
    var showsIndicators: Bool
    @ViewBuilder var content: Content
    @Environment(\.layoutDirection) private var layoutDirection
        
    init(showsIndicators: Bool = true, @ViewBuilder content: () -> Content) {
        self.showsIndicators = showsIndicators             
        self.content = content()
    }
        
    var body: some View {
       ScrollViewReader { proxy in
         ScrollView(.horizontal, showsIndicators: showsIndicators) {
             content
                 .id("RTL")
                 .onAppear {
                     if layoutDirection == .rightToLeft {
                           proxy.scrollTo("RTL", anchor: .trailing)
                     }
                 }
             }
         }
     }
}

Usage:

 ScrollViewRTL {
     HStack {
         Text("b1")
         Text("b2")
         Text("b3")
     }
 }
Related