最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

ios - How to avoid clipping of .popover content close to bottom screen edge? - Stack Overflow

programmeradmin3浏览0评论

I would like use .popover with .presentationCompactAdaptation(.popover) in an iPhone iOS 16+ app. This shows the popover not as sheet but as real popover not only on iPad but on iPhone as well.

While this works fine in general, the popover is not positioned correctly when coming close to the bottom screen edge.

In the following example the popover is positioned correctly to the top and side screen edges (buttons 1-3). Button 5 at the very bottom shows the popover above the button. However, the popover of button 4 is not shown above the button (although there is enough free space) but below the button. Since there is not enough space, the content is clipped.

This is quite strange, isn't it? Is this some bug or intended behavior? Can this be fixed?

struct PopoverTest: View {
    var body: some View {
        VStack {
            HStack {
                PopoverButton(text: "Button 1")
                Spacer()
            }
            
            Spacer()
            
            HStack {
                Spacer()
                PopoverButton(text: "Button 2")
            }
            
            Spacer()
            
            HStack {
                Spacer(minLength: 270)
                PopoverButton(text: "Button 3")
                Spacer()
            }
            
            PopoverButton(text: "Button 4")
                .padding(.top, 300)
            
            Spacer()
            
            PopoverButton(text: "Button 5")
        }
    }
}


struct PopoverButton: View {
    @State private var isPresented = false
    var text: String
    
    var body: some View {
        Button(action: { isPresented = true }) {
            Text(text)
        }
        .popover(isPresented: $isPresented) {
            VStack {
                Text("Some Line of Text 1")
                Text("Some Line of Text 2")
                Text("Some Line of Text 3")
                Text("Some Line of Text 4")
                Text("Some Line of Text 5")
                Text("Some Line of Text 6")
                Text("Some Line of Text 7")
                Text("Some Line of Text 8")
                Text("Some Line of Text 9")
            }
            .presentationCompactAdaptation(.popover)
        }
    }
}

I would like use .popover with .presentationCompactAdaptation(.popover) in an iPhone iOS 16+ app. This shows the popover not as sheet but as real popover not only on iPad but on iPhone as well.

While this works fine in general, the popover is not positioned correctly when coming close to the bottom screen edge.

In the following example the popover is positioned correctly to the top and side screen edges (buttons 1-3). Button 5 at the very bottom shows the popover above the button. However, the popover of button 4 is not shown above the button (although there is enough free space) but below the button. Since there is not enough space, the content is clipped.

This is quite strange, isn't it? Is this some bug or intended behavior? Can this be fixed?

struct PopoverTest: View {
    var body: some View {
        VStack {
            HStack {
                PopoverButton(text: "Button 1")
                Spacer()
            }
            
            Spacer()
            
            HStack {
                Spacer()
                PopoverButton(text: "Button 2")
            }
            
            Spacer()
            
            HStack {
                Spacer(minLength: 270)
                PopoverButton(text: "Button 3")
                Spacer()
            }
            
            PopoverButton(text: "Button 4")
                .padding(.top, 300)
            
            Spacer()
            
            PopoverButton(text: "Button 5")
        }
    }
}


struct PopoverButton: View {
    @State private var isPresented = false
    var text: String
    
    var body: some View {
        Button(action: { isPresented = true }) {
            Text(text)
        }
        .popover(isPresented: $isPresented) {
            VStack {
                Text("Some Line of Text 1")
                Text("Some Line of Text 2")
                Text("Some Line of Text 3")
                Text("Some Line of Text 4")
                Text("Some Line of Text 5")
                Text("Some Line of Text 6")
                Text("Some Line of Text 7")
                Text("Some Line of Text 8")
                Text("Some Line of Text 9")
            }
            .presentationCompactAdaptation(.popover)
        }
    }
}
Share Improve this question asked Mar 19 at 8:54 Andrei HerfordAndrei Herford 18.8k24 gold badges108 silver badges258 bronze badges 4
  • Use the arrowEdge option with the popover guy. – El Tomato Commented Mar 19 at 9:57
  • @ElTomato How does this solve the problem? When specifying the edge explicitly (.top is the default). With .bottom the popover of Button1 does not show. With .leading the popover of Button3 is clipped, etc. – Andrei Herford Commented Mar 19 at 11:32
  • @AndreiHerford - have you tried different devices? Running your unedited code on iPhone 15 Pro (Simulator) with iOS 17.0, I don't get the same results. The "Button 4" popover is placed above the button. Notably, the popovers for 2 and 3 show up to the left of those buttons, not underneath. – DonMag Commented Mar 19 at 16:57
  • @DonMag That is interesting. Indeed the problem does not occur on iOS 17. So this seems to be related to iOS 18. However, does anyone know a workaround? – Andrei Herford Commented Mar 21 at 9:40
Add a comment  | 

1 Answer 1

Reset to default 0

Thanks so the hint of @DonMag and after some more digging, I was able to find a solution.

It seems that this is a <s>bug</s> intended behaviour in iOS 18+. The arrowEdge is not use as a hint anymore (place the arrow here, if there is sufficient space) but as constraint (place the arrow here and clip content if necessary).

This can be solved with the following wrapper which uses different calls for iOS18 or below:

extension View {
    @ViewBuilder func autoEdgePopover<Content: View>(
        isPresented: Binding<Bool>,
        attachmentAnchor: PopoverAttachmentAnchor = .rect(.bounds),
        @ViewBuilder content: @escaping () -> Content
    ) -> some View {
        if #available(iOS 18, *) {
            self
                .popover(isPresented: isPresented, attachmentAnchor: attachmentAnchor, content: content)
        } else {
            self
                .popover(isPresented: isPresented, attachmentAnchor: attachmentAnchor, arrowEdge: .top, content: content)
        }
    }
}
发布评论

评论列表(0)

  1. 暂无评论