UIView Callout Bubble

2019-03-16 17:54发布

问题:

I want to be able to do something like the MapView callout when a user touches a UILabel in a standard view. This is not a map view! Or can I hover over a new UIView?

Can anyone point me in the right direction please?

Thanks,

回答1:

Some downloadable code to do something similar is available in this answer.



回答2:

I did this recently.

You need two UIView subclasses: one outer view (draws the background and handles dismissing the bubble) and one inner (draws the bubble itself). I called mine IMPBubbleView and IMPBubbleInternalView.

In IMPBubbleView, it sets itself to be the size of the current UIWindow, then adds itself as a subview of the window. The caller has to pass in a rectangle that the bubble should point to: work out where that is in the window by doing convertRect:toView: (a method on UIView) and passing in the IMPBubbleView.

The IMPBubbleView creates an IMPBubbleInternalView object, and adds it as a subview of self.

It needs to work out if there's room to draw the bubble either below or above the rect (so the bubble doesn't end up off the screen). You can make the bubble view take a passed in UIView object to display within it: that makes the most reusable API. You can then ask for the size of this view. Some simple maths, and set the bubbleOnTop property of IMPBubbleInternalView.

To actually draw the bubble itself, I ported some of Matt Gemmel's code (found at http://mattgemmell.com/source) to create a path for the bubble outline. I then filled it with a gradient with the following colours:

    CGFloat locations[5] = { 0.0, 0.5, 0.65, 0.65, 1.0 };
CGFloat components[20] = { 0.0, 0.0, 0.0, 1.0,  // Start color
                          58.0/255, 58.0/255, 58.0/255, 1.0,
                          58.0/255, 58.0/255, 58.0/255, 1.0,
                          91.0/255, 91.0/255, 91.0/255, 1.0,
                          144.0/255, 144.0/255, 144.0/255, 1.0 }; // End color

When you display the IMPBubbleInternalView, you can use Core Animation to make it do a fade in, or a slight enlarge then reduce, or whatever.

Finally, you need to handle taps in the IMPBubbleView (which draws the background). A tap here should dismiss the bubble. Override touchesEnded:withEvent: and use the locationInView: method on the touch object (to make sure that you're handling a tap that was outside the bubble).

I think that's about everything. I had a bunch of stuff for adding buttons (I was emulating the copy/paste menu).



回答3:

My approach would be to create an png image, in the style of the bubble (only useful for a fixed size bubble of course), Subclass UIView, and draw this image into the UIView's Background when it's created, i would also add a UILabel or UIImage depending on what i wanted to do, whether it be display text or an image.

If you wanted to do variable size images, you would want to use Quartz2D and draws the rects that you require. While this is more work, if done properly you end up with a more extensible component.

Next step is to subclass the UILabel, and add a method that responses to the touchesBegan (UIResponder) method, this will be called each time it's touched. You can then create and display your custom view to the user. Usually i would say create a delegate, however i don't think UILabel/UIView supports this.