Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
330018: popover view now contains arrow in its frame
-
@cvp seems to be a known ios13 "feature"
There are a few ideas in there -- involving safeArea anchors, etc. Something to play with while in social isolation ;)
-
@JonB said:
seems to be a known ios13 "feature"
Yes, I know it but it could be ennoying for old scripts. My new ones take this feature in account.
But, anyway, thanks to remember me. I've closed the Pythonista issue.
-
@cvp, if you solved it with safe area, could you share the code?
-
@mikael I didn't say that I solved it in a general way but I take it in account by positioning my ui objects more at right if arrow at left or more at bottom if arrow at top.
I set my first ui object at dd,dd
dd = 20 # distance between end of arrow and first ui element
-
@cvp, I do not have an iPad to test with right now, but I would try something like this:
popup = ui.View() popup_content.frame = (0,0,<desired content size here>) popup.add_subview(popup_content) popup.present(style="popover", popover_location=popup_pos, hide_title_bar=True) safe = popup.objc_instance.safeAreaInsets() popup.width = popup_content.width + safe.left + safe.right popup.height = popup_content.height + safe.top + safe.bottom popup_content.x = safe.left popup_content.y = safe.top
-
@mikael sorry, but what is popup_content as object?
And you can't change popup width and height after it has been presented
See the differences of both codes
-
@cvp, thanks for trying it out, and thanks for sharing the pictures – they make it much easier to discuss the results. What happens in the second version if you move the safe area retrieval and
popup_content.x
and.y
setting after thepresent
? -
@mikael obliged to copy instead of move the safe retrieval => 👍
import ui popup = ui.View() popup_content = ui.Label() popup_content.border_width = 3 popup_content.frame = (0,0,200,200) popup.add_subview(popup_content) #popup.present(style="popover",popover_location=(500,250),hide_title_bar=True) safe = popup.objc_instance.safeAreaInsets() popup.width = popup_content.width + safe.left + safe.right popup.height = popup_content.height + safe.top + safe.bottom #popup_content.x = safe.left #popup_content.y = safe.top popup.present(style="popover",popover_location=(500,250),hide_title_bar=True) safe = popup.objc_instance.safeAreaInsets() popup_content.x = safe.left popup_content.y = safe.top
-
-
@cvp, you’re the man!
-
@cvp, here’s a ”minimalized” version. There is still a brief delay between the popup coming up and the content showing.
import ui def present_popup(content_view, position, round_corners=True): popup = ui.View( width=content_view.width, height=content_view.height, hidden=True ) popup.add_subview(content_view) popup.present(style="popover", popover_location=position, hide_title_bar=True) safe = content_view.objc_instance.safeAreaInsets() content_view.x = safe.left content_view.y = safe.top if round_corners: content_view.corner_radius = max( safe.left, safe.top, safe.right, safe.bottom) popup.hidden = False return popup if __name__ == '__main__': popup_content = ui.Label( border_width=3, frame=(0,0,150,100), ) popup = present_popup(popup_content, (100, 100))
-
-
I did a little digging on this, to figure out how it is being solved by other developers.
First, though this would appear to many to be a bug, it actually puts the popover presentation view controller in line with how view controllers work in general. Since iOS 11+ Apple has provided a "safe area" concept which is supposed to be used by the view hierarchy to indicate what part of their content area is obscured. In the case of the popover view controller, the arrow is still part of the content area, but it obscures content.
@cvp, @mikael you are both the dudes!
I'm providing a somewhat more complex but general way below, which doesn't suffer from the delay between presentation of the popover and content. The trouble is that the safeAreaInsets() is always 0 before a view is displayed, so it can't be used to set the proper location of a view before it is visible. However, using the safeAreaLayoutGuide() and the constraint/anchor system, the content view can be made to size itself automatically to the safe area:
import ui def present_popup(content_view, position): popup = ui.View( width=content_view.width, height=content_view.height, ) popup.add_subview(content_view) content_view.objc_instance.translatesAutoresizingMaskIntoConstraints = False guide = popup.objc_instance.safeAreaLayoutGuide() anchor = content_view.objc_instance.leadingAnchor() anchor.constraintEqualToAnchor_(guide.leadingAnchor()).active = True anchor = content_view.objc_instance.trailingAnchor() anchor.constraintEqualToAnchor_(guide.trailingAnchor()).active = True anchor = content_view.objc_instance.topAnchor() anchor.constraintEqualToAnchor_(guide.topAnchor()).active = True anchor = content_view.objc_instance.bottomAnchor() anchor.constraintEqualToAnchor_(guide.bottomAnchor()).active = True popup.present(style="popover", popover_location=position, hide_title_bar=True) return popup if __name__ == '__main__': popup_content = ui.Label( text="Hello!", border_width=3, frame=(0,0,150,100), ) popup = present_popup(popup_content, (100, 100))
-
@shinyformica, I guess you are the superdude then?
-
@mikael nah, just a regular ol' dude, writin' Python for the man.
-