6

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 ?

Ouail Bellal
  • 1,554
  • 13
  • 27

5 Answers5

12

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)
Ouail Bellal
  • 1,554
  • 13
  • 27
3

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")
     }
 }
SuperGlenn
  • 572
  • 6
  • 9
0

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
        }
    }
}
0

We had a lot of problems with our arabic related our application, the modifier below solved our problem, don't forget to follow me on githup.

https://gist.github.com/metin-atalay/bdf28a604fe9678403730d14f02946ca

Metin Atalay
  • 1,375
  • 18
  • 28
0

for me this code worked. Just rotate scrollview and content of scroll view too and it start to scroll from right to left and content will have right direction.

@Environment(\.layoutDirection) private var layoutDirection

var body: some View {
    ScrollView(.horizontal, showsIndicators: false) {
        HStack(alignment: .top, spacing: 16) {
           /* content of your scroll view */
        }
        .rotation3DEffect(Angle(degrees: layoutDirection == .rightToLeft ? -180 : 0), axis: (
            x: CGFloat(0),
            y: CGFloat(layoutDirection == .rightToLeft ? -10 : 0),
            z: CGFloat(0)))
    }
    .rotation3DEffect(Angle(degrees: layoutDirection == .rightToLeft ? 180 : 0), axis: (
        x: CGFloat(0),
        y: CGFloat(layoutDirection == .rightToLeft ? 10 : 0),
        z: CGFloat(0)))
}
Vít Zadina
  • 168
  • 8