Forum Archive

How to set the background color of a popover view

shinyformica

Figured I'd post this for others, since I just got it to work.
If you've ever wanted to show a view as a popover, but colorized so it matches the theme, including the enclosing view's edges and the little arrow, here's how to do it...

import objc_util

# this code came from elsewhere on the forum: given a view, it finds the objc UIViewController which is presenting it:
def getUIViewController(view):
    UIViewController = objc_util.ObjCClass('UIViewController')
    UIView = objc_util.ObjCClass('UIView')
    viewobj = view.objc_instance
    viewResponder = viewobj.nextResponder()
    try:
        while not viewResponder.isKindOfClass_(UIViewController):
            viewResponder = viewResponder.nextResponder()
    except AttributeError:
        return None
    return viewResponder

popup = ui.View()
popup.frame = (0,0,300,50)
# "bg" is the color you want to set the popover view to
popup.background_color = bg

popup.present(style="popover",
                        popover_location=pos,
                            hide_title_bar=True)

# this is the bit that colors the enclosing view
parentvc = getUIViewController(popup)
popovervc = parentvc.popoverPresentationController()
if popovervc is not None:
    popovervc.backgroundColor = objc_util.UIColor.colorWithRed_green_blue_alpha_(*popup.background_color)

be warned that on iPhones, popover presentation is ignored and the view is presented full screen, so popovervc above will be None.

cvp

@shinyformica this line may be commented, isn'it?

    #UIView = objc_util.ObjCClass('UIView')
shinyformica

@cvp yes, that line isn't needed, I just copy-pasta'd this from a chunk of larger code...looks like I forgot to define "pos" too, which is a little complicated: it isn't simply a point in the parent coordinate system. It's a point in reference to the top-left corner of the top view in the view hierarchy which is presenting it.

I asked about getting that location a while ago, and got some good replies, so the little utility function to get that point is:

def popoverPoint(pos, sourceView):
    import objc_util
    srcobjc = sourceView.objc_instance
    topobjc = None
    parent = srcobjc.superview()
    while parent is not None:
        topobjc = parent
        parent = parent.superview()
    p = srcobjc.convertPoint_toView_(objc_util.CGPoint(*pos), topobjc)
    return (p.x,p.y)