4

The goal is to have something that looks like this:

Example of the desired result

I am aware of .rotationEffect(), and the solution provided here.

However the problem with this solution is that it does not rotate the frame, it only rotates the text itself.

The image below is from the Canvas preview in Xcode and the code underneath it.

Result using .rotationEffect()

HStack(spacing: 10) {
    Text("Distance")
        .rotationEffect(.degrees(270))
        .foregroundColor(.black)
        .minimumScaleFactor(0.01)

    Rectangle()
         .foregroundColor(.black)
         .frame(width: 3)
         .padding([.top, .bottom])
    Spacer()
}

As you can see, the text goes outside the frame and the frame keeps its original width, making it difficult to have the text hug the side of the view and have the vertical line hug the side of the text.

The only way I have been able to figure out how to get the desired result is to use the .offset(x:) modifier. But this feels messy and could lead to bugs down the road I think.

Is there any way to be able to rotate the frame along with the text?

Sunderam Dubey
  • 1
  • 11
  • 20
  • 40
NSSpeedForce
  • 127
  • 9
  • This might help... https://stackoverflow.com/questions/60581061/rotate-a-text-view-and-its-frame-in-swiftui – Stoic Jun 18 '22 at 19:34

1 Answers1

5

If we talk about dynamic detection, then we need to measure text frame before rotation and apply to frame size of changed width/height

Note: of course in simplified variant frame width can be just hardcoded

enter image description here

Here is main part:

@State private var size = CGSize.zero

var body: some View {
    HStack(spacing: 10) {
        Text("Distance")
            .fixedSize()                  // << important !!
            .background(GeometryReader {
                Color.clear
                    .preference(key: ViewSizeKey.self, value: $0.frame(in: .local).size)
            })
            .onPreferenceChange(ViewSizeKey.self) {
                self.size = $0                        // << here !!
            }
            .rotationEffect(.degrees(270))
            .frame(width: size.height, height: size.width) // << here !!

Used preference key:

public struct ViewSizeKey: PreferenceKey {
    public typealias Value = CGSize
    public static var defaultValue = CGSize.zero
    public static func reduce(value: inout Value, nextValue: () -> Value) {
    }
}

Test module/dependecies on GitHub

Asperi
  • 228,894
  • 20
  • 464
  • 690
  • Thank you. I wasn't sure what `ViewSizeKey` was supposed to be, so I had to do some reading [here](https://swiftontap.com/preferencekey). Maybe add a small note about what it is for anyone else that might not know and get the error `Cannot find 'ViewSizeKey' in scope`. Other than that, this answer worked well. Thanks again! – NSSpeedForce Jun 18 '22 at 20:01
  • It is a preference key it is declared in referenced project in common module https://github.com/Asperi-Demo/4SwiftUI/blob/master/PlayOn_iOS/PlayOn_iOS/Helpers/PreferenceKeys.swift – Asperi Jun 18 '22 at 20:02