我在关注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()修饰符,但这两种方法都没有解决问题。
有人能解释一下为什么这种重新定位是必要的,如果有一个更好的方法来处理这一点?
2条答案
按热度按时间lvjbypge1#
请注意,示例代码使用
rotationEffect
创建了8个BadgeSymbol
,它们围绕底部旋转到不同的Angular 。这里的关键点是,
ZStack
使用视图的“逻辑”框架将其视图居中,这不受rotationEffect
的影响。让我们只考虑2BadgeSymbol
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,以便居中。
afdcj2ne2#
原因是
ZStack
中的.scaleEffect(1.0 / 4.0, anchor: .top)
在将badgeSymbols
锚定在顶部时会缩放.scaleEffect(1.0 / 4.0, anchor: .top)
。这会导致子视图向其顶部收缩,使其看起来位于视图容器的顶部,但实际上badgeSymbols
位于ZStack
的中间并占据了它所需的所有可用空间,缩放只是使视图向上移动的错觉。如果您设置.scaleEffect(1.0 / 4.0)
没有锚,并删除.position
,badgeSymbols
将按预期居中。