SwiftUI .rotationEffect() framing and offsetting
You need to adjust the frame yourself in this case. That requires capturing what the frame is, and then applying the adjustment.
First, to capture the existing frame, create a preference, which is a system for passing data from child views to their parents:
private struct SizeKey: PreferenceKey {
static let defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
}
extension View {
func captureSize(in binding: Binding<CGSize>) -> some View {
overlay(GeometryReader { proxy in
Color.clear.preference(key: SizeKey.self, value: proxy.size)
})
.onPreferenceChange(SizeKey.self) { size in binding.wrappedValue = size }
}
}
This creates a new .captureSize(in: $binding)
method on Views.
Using that, we can create a new kind of View that rotates its frame:
struct Rotated<Rotated: View>: View {
var view: Rotated
var angle: Angle
init(_ view: Rotated, angle: Angle = .degrees(-90)) {
self.view = view
self.angle = angle
}
@State private var size: CGSize = .zero
var body: some View {
// Rotate the frame, and compute the smallest integral frame that contains it
let newFrame = CGRect(origin: .zero, size: size)
.offsetBy(dx: -size.width/2, dy: -size.height/2)
.applying(.init(rotationAngle: CGFloat(angle.radians)))
.integral
return view
.fixedSize() // Don't change the view's ideal frame
.captureSize(in: $size) // Capture the size of the view's ideal frame
.rotationEffect(angle) // Rotate the view
.frame(width: newFrame.width, // And apply the new frame
height: newFrame.height)
}
}
And for convenience, an extension to apply it:
extension View {
func rotated(_ angle: Angle = .degrees(-90)) -> some View {
Rotated(self, angle: angle)
}
}
And now your code should work as you expect:
struct TextAloneView: View {
var body: some View {
VStack {
Text("Horizontal text")
Text("Vertical text").rotated()
}
}
}
SwiftUI: Text has not the full width of screen after rotation
Here is a demo of possible approach. Prepared with Xcode 12.1 / iOS 14.1
struct DemoView: View {
var body: some View {
HStack {
RotatedText(text: lorem, angle: Angle(degrees: 90))
RotatedText(text: lorem, angle: Angle(degrees: -90))
}
}
}
struct RotatedText: View {
let text: String
let angle: Angle
var color: Color = .blue
var body: some View {
color.overlay(
GeometryReader { gp in
VStack {
Text(text)
.frame(width: gp.size.height, height: gp.size.width)
.rotationEffect(angle)
}.frame(width: gp.size.width, height: gp.size.height)
}
)
}
}
How to build scrollable side menu using text rotation (or something similar) in SwiftUI?
I did found a good solution using Attempt 2 and rotating the entire Text view using @robniper detailed answer here : https://stackoverflow.com/a/59802487/5541378
How to make SwiftUI Picker Wrap Text
A solution appears a bit complicated because Picker is not native SwiftUI control, but has UIPickerView
at backend, so we need combination of already mentioned one to get rid of compression contains and another one to calculate most long label and compress picker explicitly.
Main part is
@State private var maxWidth = CGFloat.zero
@State private var width = CGFloat.infinity
var body: some View {
Picker("", selection: $selection) {
ForEach( ...
// Row/Label view is here
.background(GeometryReader {
Color.clear.preference(key: ViewWidthKey.self,
value: $0.frame(in: .local).size.width)
})
.onPreferenceChange(ViewWidthKey.self) {
self.maxWidth = max($0, maxWidth)
width = max($0, maxWidth)
}
}
}
.pickerStyle(.wheel)
.frame(maxWidth: width + 2 * 20 /* padding on both sides */)
}
Tested with Xcode 13.4 / iOS 15.5
Test code on GitHub
Automatic adjust font size in Text() of Swiftui?
Use minimumScaleFactor(_:)
https://developer.apple.com/documentation/swiftui/text/minimumscalefactor(_:)
struct ContentView: View {
var body: some View {
VStack{
Text("Test string")
.minimumScaleFactor(0.1) //<--Here
.frame(width: 15, height: 15)
}
}
}
Related Topics
Sub-Classing Nstextstorage Causes Significant Memory Issues
How to Animate Transition Between Views in Swiftui
How to Create String Split Extension with Regex in Swift
How to Add a Double Tap Gesture Recognizer in Swift
Swift 4 Codable - API Provides Sometimes an Int Sometimes a String
Swift Uipasteboard Not Copying Png
How to Detect Switch Between MACos Default & Dark Mode Using Swift 3
How to Cast an _Nsmallocblock_ to Its Underlying Type in Swift 3
Typecasting or Initialization, Which Is Better in Swift
How to Benchmark Swift Code Execution
How to Make a Https Request to a Server in Swift
How to Detect a 'Click' Gesture in Swiftui Tvos
This Class Is Not Key Value Coding-Compliant for the Key Name.'
Uitesting Xcode 7: How to Tell If Xcuielement Is Visible
How to Make Alphabetically Section Headers in Table View with a Mutable Data Source
Ycombinator Not Working in Swift