SwiftUI .rotationEffect() 框架和偏移 [英] SwiftUI .rotationEffect() framing and offsetting

查看:40
本文介绍了SwiftUI .rotationEffect() 框架和偏移的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

将 .rotationEffect() 应用于 Text 时,它会按预期旋转文本,但其框架保持不变.当将旋转视图与非旋转视图(例如 HStack 的 VStack 堆叠在一起时,这会成为一个问题,导致它们重叠.

When applying .rotationEffect() to a Text, it rotates the text as expected, but its frame remains unchanged. This becomes an issue when stacking rotated views with non-rotated views, such as with a VStack of HStack, causing them to overlap.

我最初认为rotationEffect会简单地将Text的frame更新为垂直,但事实并非如此.

I initially thought the rotationEffect would simply update the frame of the Text to be vertical, but this is not the case.

我已经尝试手动设置帧大小和(如果需要,偏移)文本,哪种工作,但我不喜欢这个解决方案,因为它需要一些猜测和检查文本将出现的位置,如何大做框架等

I've tried manually setting the frame size and (if needed, offsetting) the Text, which sort of works, but I don't like this solution because it requires some guessing and checking of where the Text will appear, how big to make the frame, etc.

这就是旋转文本的完成方式,还是有更优雅的解决方案?

Is this just how rotated text is done, or is there a more elegant solution to this?

struct TextAloneView: View {

    var body: some View {
        VStack {
            Text("Horizontal text")
            Text("Vertical text").rotationEffect(.degrees(-90))
        }
    }
}

重叠文本

推荐答案

在这种情况下,您需要自己调整框架.这需要捕捉框架是什么,然后应用调整.

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

这会在视图上创建一个新的 .captureSize(in: $binding) 方法.

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 .rotationEffect() 框架和偏移的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆