假设我在一个工作表中有一个自定义视图,就像这样
VStack {
Text("Title")
Text("Some very long text ...")
}
.padding()
.presentationDetents([.height(250)])
我如何获得VStack的确切高度并将其传递给presentationents修饰符,以便工作表的高度正好是内部内容的高度?
使用@jnpdx的一般想法,包括一些更新,例如读取覆盖层的大小而不是背景,以下是对我有用的:
struct ContentView: View {
@State private var showSheet = false
@State private var sheetHeight: CGFloat = .zero
var body: some View {
Button("Open sheet") {
showSheet = true
}
.sheet(isPresented: $showSheet) {
VStack {
Text("Title")
Text("Some very long text ...")
}
.padding()
.overlay {
GeometryReader { geometry in
Color.clear.preference(key: InnerHeightPreferenceKey.self, value: geometry.size.height)
}
}
.onPreferenceChange(InnerHeightPreferenceKey.self) { newHeight in
sheetHeight = newHeight
}
.presentationDetents([.height(sheetHeight)])
}
}
}
struct InnerHeightPreferenceKey: PreferenceKey {
static var defaultValue: CGFloat = .zero
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}
您可以使用GeometryReader
和PreferenceKey
读取大小,然后将其写入状态变量。在我的示例中,我存储了整个大小,但您可以调整它以仅存储高度,因为这可能是您需要的唯一参数。
struct ContentView: View {
@State private var showSheet = false
@State private var size: CGSize = .zero
var body: some View {
Button("View sheet") {
showSheet = true
}
.sheet(isPresented: $showSheet) {
VStack {
Text("Title")
Text("Some very long text ...")
}
.padding()
.background(
GeometryReader { geometryProxy in
Color.clear
.preference(key: SizePreferenceKey.self, value: geometryProxy.size)
}
)
.onPreferenceChange(SizePreferenceKey.self) { newSize in
size.height = newSize.height
}
.presentationDetents([.height(size.height)])
}
}
}
struct SizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) { value = nextValue() }
}
更可重用
struct InnerHeightPreferenceKey: PreferenceKey {
static var defaultValue: CGFloat = .zero
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { value = nextValue() }
}
extension View {
func fixedInnerHeight(_ sheetHeight: Binding<CGFloat>) -> some View {
padding()
.background {
GeometryReader { proxy in
Color.clear.preference(key: InnerHeightPreferenceKey.self, value: proxy.size.height)
}
}
.onPreferenceChange(InnerHeightPreferenceKey.self) { newHeight in sheetHeight.wrappedValue = newHeight }
.presentationDetents([.height(sheetHeight.wrappedValue)])
}
}
struct ExampleView: View {
@State private var showSheet = false
@State private var sheetHeight: CGFloat = .zero
var body: some View {
Button("Open sheet") {
showSheet = true
}
.sheet(isPresented: $showSheet) {
VStack {
Text("Title")
Text("Some very long text ...")
}
.fixedInnerHeight($sheetHeight)
}
}
}
1。Сreate一个Сustom修饰符,返回任何视图的高度(这是一个非常有用的修饰符,您很可能会在其他地方使用):
struct GetHeightModifier: ViewModifier {
@Binding var height: CGFloat
func body(content: Content) -> some View {
content.background(
GeometryReader { geo -> Color in
DispatchQueue.main.async {
height = geo.size.height
}
return Color.clear
}
)
}
}
2。使用自定义修饰符来获取高度
struct ContentView: View {
@State private var showSheet = false
@State private var sheetHeight: CGFloat = .zero
var body: some View {
Button("Open sheet") {
showSheet = true
}
.sheet(isPresented: $showSheet) {
VStack {
Text("Title")
Text("Some very long text ...")
}
.padding()
.modifier(GetHeightModifier(height: $sheetHeight))
.presentationDetents([.height(sheetHeight)])
}
}
}
struct ContentView: View {
@State private var showingSheet = false
let heights = stride(from: 0.1, through: 1.0, by: 0.1).map { PresentationDetent.fraction($0) }
var body: some View {
Button("Show Sheet") {
showingSheet.toggle()
}
.sheet(isPresented: $showingSheet) {
Text("Random text ")
.presentationDetents(Set(heights))
}
}
}