VStack 子级填充不扩展其父级

问题描述

我正在尝试使警报视图的按钮适合父 vstack。但我只能看到两个选项:

  1. 按钮宽度不变,没有框架修饰符。这并不理想,因为按钮不够宽

    Alert without max width

  2. 将框架修饰符设置为 .frame(maxWidth: .infinity)。这并不理想,因为它不会同时填充其父级,而且还会使其延伸到屏幕的边缘。

    Alert with max width

我真正想要的是,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) 或类似的东西来解释短消息。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...