问题描述
我正在尝试使警报视图的按钮适合父 vstack。但我只能看到两个选项:
-
按钮宽度不变,没有框架修饰符。这并不理想,因为按钮不够宽
-
将框架修饰符设置为
.frame(maxWidth: .infinity)
。这并不理想,因为它不会同时填充其父级,而且还会使其延伸到屏幕的边缘。
我真正想要的是,vstack 保持其宽度,而按钮只是填充到边缘。没有扩展 vstack。 vstack 的大小由标题和消息定义,而不是由按钮定义。这可以通过 SwiftUI 实现吗?
代码:
Color.white
.overlay(
ZStack {
Color.black.opacity(0.4)
.edgesIgnoringSafeArea(.all)
vstack(spacing: 15) {
Text("Alert View")
.font(.headline)
Text("This is just a message in an alert")
Button("Okay",action: {})
.padding()
.frame(maxWidth: .infinity)
.background(Color.yellow)
}
.padding()
.background(Color.white)
}
)
解决方法
正如评论中提到的,如果您希望宽度与消息大小相关联,则必须使用 PreferenceKey
将值向上传递到视图层次结构:
struct ContentView: View {
@State private var messageWidth: CGFloat = 0
var body: some View {
Color.white
.overlay(
ZStack {
Color.black.opacity(0.4)
.edgesIgnoringSafeArea(.all)
VStack(spacing: 15) {
Text("Alert View")
.font(.headline)
Text("This is just a message in an alert")
.background(GeometryReader {
Color.clear.preference(key: MessageWidthPreferenceKey.self,value: $0.frame(in: .local).size.width)
})
Button("Okay",action: {})
.padding()
.frame(width: messageWidth)
.background(Color.yellow)
}
.padding()
.background(Color.white)
}
.onPreferenceChange(MessageWidthPreferenceKey.self) { pref in
self.messageWidth = pref
}
)
}
struct MessageWidthPreferenceKey : PreferenceKey {
static var defaultValue: CGFloat { 0 }
static func reduce(value: inout Value,nextValue: () -> Value) {
value = value + nextValue()
}
}
}
我敢打赌,在某些情况下,您还想设置最小宽度(例如警报消息只有一个字长),因此在实际应用中可能会使用 max(minValue,messageWidth)
或类似的东西来解释短消息。