SwiftUI .popover 框架大小不正确

问题描述 投票:0回答:2

在 iOS 16.4 中,我们现在可以在

.presentationCompactAdaptation(.none)
中使用
.popover
在 iOS 上实现真正的弹出窗口(紧凑的屏幕尺寸)。

SomeView()
    .popover(isPresented: $isPopoverOpen) {
        Text("Hello world!")
            .fixedSize(horizontal: false, vertical: true)
            .padding()
            .presentationCompactAdaptation(.none)
    }

这会给我们类似的东西:

太棒了,它按预期工作!

当弹出窗口中的

Text()
跨越多行时,就会出现问题。由于某种原因,弹出窗口的高度只会增长到一定高度(~3 行,带有非动态
.body
字体)。下面是使用一些 Lorem Ipsum 文本来说明该问题。请注意,由于弹出窗口高度太短,末端如何被剪掉:

如何使弹出框适合

Text()
内容?我可以静态定义高度,但我希望弹出窗口能够完美地适合内容。

ios swiftui popover swiftui-sheet
2个回答
2
投票

您可以使用此方法获取文本元素的高度。

为此,您将获取文本的高度并设置您收到的高度。 这就是代码的样子

struct ContentLengthPreference: PreferenceKey {
    static var defaultValue: CGFloat { 0 }
    
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value = nextValue()
    }
}

struct ContentView: View {
    @State private var isPopoverOpen = true
    @State var textHeight: CGFloat = 0 // <-- this
    
    var body: some View {
        Text("Hello, World!")
            .popover(isPresented: $isPopoverOpen) {
                Text("""
                        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
                        """
                )
                .overlay(
                    GeometryReader { proxy in
                        Color
                            .clear
                            .preference(key: ContentLengthPreference.self,
                                        value: proxy.size.height) // <-- this
                    }
                )
                .onPreferenceChange(ContentLengthPreference.self) { value in // <-- this
                    DispatchQueue.main.async {
                        print (value)
                        self.textHeight = value
                    }
                }
                .fixedSize(horizontal: false, vertical: true)
                .frame(height: textHeight)
                .padding()
                .presentationCompactAdaptation(.none)
                
            }
    }
}

长文本弹出框

带有短文本的弹出框

快乐编码!


0
投票

你觉得这个怎么样?

您可以使用布局协议协商大小。

import SwiftUI

struct PopoverContainer: Layout {
    func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
        guard subviews.count == 1 else {
            fatalError("You need to implement your layout!")
        }
        var p = proposal
        p.width = p.width ?? UIScreen.main.bounds.width
        p.height = p.height ?? UIScreen.main.bounds.height

        return subviews[0].sizeThatFits(p) // negotiates possible size
    }
    
    func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
        // entrusts default
    }
}

struct ContentView: View {
    @State private var isPopoverOpen = true
    var body: some View {
        Text("Hello, World!")
            .popover(isPresented: $isPopoverOpen) {
                PopoverContainer {
                    Text("""
                            Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
                            """
                    )
                    .fixedSize(horizontal: false, vertical: true)
                    .padding()
                }
                .presentationCompactAdaptation(.none)
                
            }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.