You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI旋转文本侧向显示时如何同步旋转对应布局框架

问题核心

目标实现侧边竖排文本紧贴分隔线的布局效果:
目标效果示例
SwiftUI内置的.rotationEffect()是渲染层修饰符,仅对视图的绘制内容做仿射变换,不会修改视图参与布局计算的框架尺寸,直接使用会出现文本溢出、原横向占位残留的问题:
使用.rotationEffect()得到的效果
对应测试代码:

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

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

靠.offset(x:)硬编码位置属于临时适配方案,遇到动态字体调整、多语言文案长度变化、屏幕尺寸适配时很容易出现错位,稳定性极差。

可行方案

不需要硬写偏移值,用原生能力就能实现旋转后布局框架同步适配,有两种常用实现:

方案1:固定90/270度竖排文本适配

如果只需要做横向文本转竖排(旋转角度固定为90度或270度),直接调换文本宽高作为旋转后的布局框架即可,封装成可复用组件:

// 竖排旋转文本组件
struct VerticalText: View {
    let content: String
    let rotateAngle: Double
    
    init(_ content: String, rotateAngle: Double = 270) {
        self.content = content
        self.rotateAngle = rotateAngle
    }
    
    // 读取文本原始内在尺寸
    private var originalSize: CGSize {
        UIHostingController(rootView: Text(content)).view.intrinsicContentSize
    }
    
    var body: some View {
        Text(content)
            .foregroundColor(.black)
            .fixedSize()
            .rotationEffect(.degrees(rotateAngle))
            // 旋转90/270度时宽高互换,直接给外层容器设置对应尺寸
            .frame(
                width: originalSize.height,
                height: originalSize.width
            )
    }
}

替换原有代码中的Text调用即可,布局系统会自动按照旋转后的实际尺寸计算相邻视图的位置,不需要额外调整偏移:

HStack(spacing: 10) {
    VerticalText("Distance")
        .minimumScaleFactor(0.01)

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

方案2:任意角度旋转的布局适配

如果需要支持任意角度的旋转,同时同步更新布局框架,可以通过几何变换计算旋转后的实际占用边界,将外层容器尺寸匹配到旋转后的边界范围:

extension View {
    func rotationWithSyncedLayout(_ angle: Angle, anchor: UnitPoint = .center) -> some View {
        GeometryReader { proxy in
            let originalSize = proxy.size
            // 计算旋转后的实际占用矩形尺寸
            let rotatedBounds = CGRect(origin: .zero, size: originalSize)
                .applying(CGAffineTransform(rotationAngle: CGFloat(angle.radians)))
            
            self
                .rotationEffect(angle, anchor: anchor)
                // 外层容器设置为旋转后的实际尺寸
                .frame(width: rotatedBounds.width, height: rotatedBounds.height)
                // 对齐位置,避免内容偏移
                .offset(
                    x: (rotatedBounds.width - originalSize.width) / 2,
                    y: (rotatedBounds.height - originalSize.height) / 2
                )
        }
        .fixedSize()
    }
}

使用时直接替换原有.rotationEffect调用即可,支持任意旋转角度,自动同步布局框架:

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

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

两种方案都基于视图的实际尺寸计算布局,会自动适配动态字体大小、文案长度变化,不会因为系统设置或者内容调整出现布局错位。


内容的提问来源于stack exchange,提问作者NSSpeedForce

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 09:12:19