您正在寻找的是PreferenceKeys
. 本质上,它们会跟踪某些视图的大小,然后您可以使用这些大小来计算您需要的内容。它们最常用于使多个视图保持相同大小,即使它们具有不同的大小。我给你一个长短的解决方案:
长解决方案:
struct SpacerPrefKeyView: View {
@State private var textWidth: CGFloat = 10
@State private var hStackWidth: CGFloat = 10
let X: CGFloat = 20
var body: some View {
HStack {
Spacer()
.frame(width: (hStackWidth - textWidth) * (X/100))
Text("Hello, World!")
.background(GeometryReader { geometry in
Color.clear.preference(
//This sets the preference key value with the width of the background view
key: TextWidthPrefKey.self,
value: geometry.size.width)
})
Spacer()
}
.background(GeometryReader { geometry in
Color.clear.preference(
//This sets the preference key value with the width of the background view
key: HStackWidthPrefKey.self,
value: geometry.size.width)
})
.onPreferenceChange(TextWidthPrefKey.self) {
// This keeps track of the change of the size
textWidth = $0
}
.onPreferenceChange(HStackWidthPrefKey.self) {
// This keeps track of the change of the size
hStackWidth = $0
}
}
}
private extension SpacerPrefKeyView {
struct TextWidthPrefKey: PreferenceKey {
static let defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat,
nextValue: () -> CGFloat) {
value = max(value, nextValue())
}
}
struct HStackWidthPrefKey: PreferenceKey {
static let defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat,
nextValue: () -> CGFloat) {
value = max(value, nextValue())
}
}
}
感谢 FiveStarBlog 和 Twitter 上的@ramzesenok 的简短解决方案:
struct SpacerPrefKeyView: View {
@State private var textSize: CGSize = CGSize(width: 10, height: 10)
@State private var hStackSize: CGSize = CGSize(width: 10, height: 10)
let X: CGFloat = 20
var body: some View {
HStack {
Spacer()
.frame(width: (hStackSize.width - textSize.width) * (X/100))
Text("Hello, World!")
.copySize(to: $textSize)
Spacer()
}
.copySize(to: $hStackSize)
}
}
并使用扩展名:
extension View {
func readSize(onChange: @escaping (CGSize) -> Void) -> some View {
background(
GeometryReader { geometryProxy in
Color.clear
.preference(key: SizePreferenceKey.self, value: geometryProxy.size)
}
)
.onPreferenceChange(SizePreferenceKey.self, perform: onChange)
}
func copySize(to binding: Binding<CGSize>) -> some View {
self.readSize { size in
binding.wrappedValue = size
}
}
}
他们做同样的事情,但是扩展非常巧妙地处理它,而您的视图中没有额外的代码。我把它贴出来让你看看它是如何PreferenceKeys
工作的。