ios SwiftUI中旋转对象组成的视图的参考框架理解

mlnl4t2r  于 12个月前  发布在  iOS
关注(0)|答案(2)|浏览(88)

我在关注this SwiftUI tutorial,遇到了Badge. swift中badgeSymbols的定位问题。相关代码如下:
Badge.swift:(应用重新定位的位置)

import SwiftUI

struct Badge: View {
    var badgeSymbols: some View {
        ForEach(0..<8) { index in
            RotatedBadgeSymbol(
                angle: .degrees(Double(index) / Double(8)) * 360.0
            )
        }
        .opacity(0.5)
    }

    var body: some View {
        ZStack {
            BadgeBackground()

            GeometryReader { geometry in
                badgeSymbols
                    .scaleEffect(1.0 / 4.0, anchor: .top)
                    .position(x: geometry.size.width / 2.0, y: (3.0 / 4.0) * geometry.size.height) // <--------- this is the re-positioning, particularly the "y" component
            }
        }
        .scaledToFit()
    }
}

#Preview {
    Badge()
}

字符串
RotatedBadgeSymbol.swift:

import SwiftUI

struct RotatedBadgeSymbol: View {
    let angle: Angle

    var body: some View {
        BadgeSymbol()
            .padding(-60)
            .rotationEffect(angle, anchor: .bottom)
    }
}

#Preview {
    RotatedBadgeSymbol(angle: Angle(degrees: 5))
}


swift(不太相关--重要的是它返回的视图是一个路径):

struct BadgeSymbol: View {
    static let symbolColor = Color(red: 79.0 / 255, green: 79.0 / 255, blue: 191.0 / 255)

    var body: some View {
        GeometryReader { geometry in
            Path { path in
                let width = min(geometry.size.width, geometry.size.height)
                let height = width * 0.75
                let spacing = width * 0.030
                let middle = width * 0.5
                let topWidth = width * 0.226
                let topHeight = height * 0.488

                path.addLines([
                    CGPoint(x: middle, y: spacing),
                    CGPoint(x: middle - topWidth, y: topHeight - spacing),
                    CGPoint(x: middle, y: topHeight / 2 + spacing),
                    CGPoint(x: middle + topWidth, y: topHeight - spacing),
                    CGPoint(x: middle, y: spacing)
                ])

                path.move(to: CGPoint(x: middle, y: topHeight / 2 + spacing * 3))
                path.addLines([
                    CGPoint(x: middle - topWidth, y: topHeight + spacing),
                    CGPoint(x: spacing, y: height - spacing),
                    CGPoint(x: width - spacing, y: height - spacing),
                    CGPoint(x: middle + topWidth, y: topHeight + spacing),
                    CGPoint(x: middle, y: topHeight / 2 + spacing * 3)
                ])
            }
            .fill(Self.symbolColor)
        }
    }
}


我很困惑为什么badgeSymbols需要在ZStack中重新定位,特别是考虑到ZStack应该将其子对象居中。我最初认为badgeSymbols作为一个组合对象会自动居中。
我的假设是,rotationEffect可能会在视图添加到ZStack之后应用。这是正确的吗?这种行为的潜在原因是什么?
我尝试过使用Group {...}来“扁平化”badgeSymbols,并尝试添加.drawingGroup()修饰符,但这两种方法都没有解决问题。
有人能解释一下为什么这种重新定位是必要的,如果有一个更好的方法来处理这一点?

lvjbypge

lvjbypge1#

请注意,示例代码使用rotationEffect创建了8个BadgeSymbol,它们围绕底部旋转到不同的Angular 。
这里的关键点是,ZStack使用视图的“逻辑”框架将其视图居中,这不受rotationEffect的影响。让我们只考虑2 BadgeSymbol s的情况-一个旋转180度,另一个根本没有旋转。假设BadgeSymbol的高度为h。这两个BadgeSymbol s在组合到ZStack中时将 * 看起来 * 具有高度2 * h,
x1c 0d1x的数据
但就ZStack所能看到的来说,这些BadgeSymbol s具有相同的帧。
因此,ZStack将未旋转的BadgeSymbol的中心放在其中心,旋转的BadgeSymbol出现在其下方。这里我突出显示了ZStack的框架及其中心。ZStack也有高度h。



请注意,这并不是我们想要的。我们希望将两个BadgeSymbol向上移动一点,以便其“视觉”中心与ZStack的中心相同。这就是为什么我们需要更改BadgeSymbol s的位置。我们希望徽章符号具有逻辑y位置0,而不是默认中心位置(即h / 2),基本上将其向上移动h / 2。
然而,在代码中,还有一个scaleEffect,带有anchor: .top。就像rotationEffect一样,这不会改变任何东西的帧-这是一个纯粹的视觉效果。现在它看起来像这样(红色边框代表ZStack帧,和以前一样)



显然,它应该向下移动h / 4,这正是代码所做的。geometry.size.height只是“h”。y位置是3 * h / 4,因为它将h / 4添加到h / 2(否则BadgeSymbol的位置是s)。
一般来说,如果比例尺是1 / n,那么位置应该是((n - 1)/ n)* h,以便居中。

afdcj2ne

afdcj2ne2#

原因是ZStack中的.scaleEffect(1.0 / 4.0, anchor: .top)在将badgeSymbols锚定在顶部时会缩放.scaleEffect(1.0 / 4.0, anchor: .top)。这会导致子视图向其顶部收缩,使其看起来位于视图容器的顶部,但实际上badgeSymbols位于ZStack的中间并占据了它所需的所有可用空间,缩放只是使视图向上移动的错觉。如果您设置.scaleEffect(1.0 / 4.0)没有锚,并删除.positionbadgeSymbols将按预期居中。

相关问题