MapKit: How do I get and set the collision frame rectangle of an annotation view? - ios

MKAnnotationViews documentation says
Managing Collisions Between Annotation Views
var collisionMode: MKAnnotationView.CollisionMode
The collision mode to use when interpreting the collision frame rectangle.
enum MKAnnotationView.CollisionMode
Constants indicating how to interpret the collision frame rectangle of an annotation view.
I'd like to debug some collision behaviour that I don't understand.
So how do I get the collision frame rectangle that is referenced in the MapKit documentation? I'll probably try to draw this rectangle for visual debugging.
How do I set the collision frame rectangle? Maybe not directly, but which of the many involved views determines this rectangle?
This is the only reference of this term that I found in MapKit
Edit
Is this collision frame rectangle only used to make clusters or is it also used to hide the cluster with a lower display priority?
I have two AnnotationViews visually drawn on top of each other. One has displayPriority = .required, one has displayPriority = .defaultHigh. One should disappear. But where are their collision frame rectangles? Do they really overlap?

I found an explanation here. It says:
collisionMode: An MKAnnotationView.CollisionMode. Two annotation views with the same clusteringIdentifier will be replaced by a cluster annotation if the map is zoomed out so far that they collide.
But what constitutes a collision between two annotation views? To know that, we need a collision edge. It might be:
.rectangle: The edge is the view’s frame.
.circle: The edge is the largest circle inscribable in and centered within the view’s frame.
EDIT:
The docs say: The most efficient way to provide the content for an annotation view is to set its image property. The annotation view sizes itself automatically to the image you specify and draws that image for its contents. Additionally, there are other properties that may influence the frame property. So it is this automatically adjusted framethat determines the collision frame.

Related

Get frame of SceneKit node in app window?

I'm hoping to overlay a UIView (specifically a highlight box with some text, etc) over an object rendered in SceneKit, but I'm encountering an issue: I don't know exactly where the object will be onscreen at the time.
Is there a way to get the CGRect frame of a SCNNode's current position within the SCNView? Even just a center point for the node would be helpful, but ideally it would give the whole frame, indicating how much vertical and horizontal space the geometry was taking up onscreen as well.
I've searched in the documentation and online for various references to "frames" and "bounds" relative to an SCNNode, but all I'm finding is stuff about the coordinate system within the scene.
Is there no way of translating a SCNNode's position in a scene into the frame coordinates of the view, or the app window?
Check the post about calculating the projected size of an object.
Performance wise, it is much better to use SpriteKit in SceneKit if you want to overlay 2D contents. Check the overlaySKScene property of SCNSceneRenderer.

What does setting CALayer's bounds.origin do?

In CALayer's API, 'position' is used for setting the position of the layer.
By my own testing, setting bounds.origin does not do anything. Am I missing something?
The bounds.origin controls where the origin of the layer's coordinate system is, relative to the layer's frame in its superlayer. Changing it has two visible effects:
The position of sublayers of the layer. For example, when you scroll a UIScrollView, the scroll view doesn't change its subview's frames. It simply changes its bounds.origin. I suggest setting up a toy app with a scroll view and doing NSLog("scroll view bounds = %#", NSStringFromCGRect(scrollView.bounds)); from a timer or some other trigger to get a sense of what's happening.
The origin of the graphics context coordinate system in drawInContext:. Mostly commonly you would see this effect in a view's drawRect: method. Your CGContext inside drawRect: will have been translated by the self.bounds.origin.
You may find it helpful to read about “View Geometry and Coordinate Systems” in the View Programming Guide for iOS and “Layer Objects Define Their Own Geometry” in the Core Animation Programming Guide, although really neither of them have a good discussion of the bounds origin.
Changing the bounds rectangle changes the position and size of the content in the coordinate system of the layer itself. Changing the frame (or position) changes the position of the layer in the coordinate system of its super layer. Usually you only want to change the frame, not the bounds.

Adjust MkMapView Annotation

I'm adding annotations to an MkMapView and am using a custom image to do so. My custom image is box shaped with a little triangular arrow that's supposed to be right on the place that's being annotated. It seems like MapView by default annotates using the geometric center of the image. What's the best way to design around this problem? Manually moving the icon? Creating the icon in a specific way?
Here's the Apple docs for MKAnnotationView's centerOffset property:
By default, the center point of an annotation view is placed at the coordinate point of the associated annotation. You can use this property to reposition the annotation view as needed. This x and y offset values are measured in pixels. Positive offset values move the annotation view down and to the right, while negative values move it up and to the left.

UIInterfaceOrientation, CGAffineTransform, Frame, Bounds and Center

Can somebody point me to a good primer on the above, and what happens to one when you mess with the others? It seems as though no matter what I do, once I start messing with either the status bar orientation or the view transform (even if all I'm doing is 90-degree rotations), I can count on my views ending up sideways, upside down and backwards, and on a frustrating afternoon of trial and error trying to get them straightened out. I'm sure it all makes sense once you know the logic and what order everything's applied in, but so far, empirically, I haven't been able to figure it out.
I don't know of a good single document primer on the subject, but the following is what I've learned from experience and reading the docs.
center, bounds, and frame
If you set frame then center and bounds will be updated. If you set center or bounds then frame will be updated. Frame is a convenience method for manipulating center and bounds using the superview's coordinate system.
From UIView Class Reference:
The geometry of a view is defined by its frame, bounds, and center properties. The frame defines the origin and dimensions of the view in the coordinate system of its superview and is commonly used during layout to adjust the size or position of the view. The center property can be used to adjust the position of the view without changing its size. The bounds defines the internal dimensions of the view as it sees them and is used almost exclusively in custom drawing code. The size portion of the frame and bounds rectangles are coupled together so that changing the size of either rectangle updates the size of both.
See The Relationship of the Frame, Bounds, and Center Properties for more details.
transform
If you set the transform property to something besides the identity transform, frame is undefined. If you set the transform to something else, you should only manipulate the view geometry using center (to position the view in it's superview) and bounds (to adjust the size of the view). Here's the relevant info from UIView Class Reference:
The origin of the transform is the value of the center property, or the layer’s anchorPoint property if it was changed. (Use the layer property to get the underlying Core Animation layer object.) The default value is CGAffineTransformIdentity.
...
Warning If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored.
See Coordinate System Transforms for more details.
UIInterfaceOrientation
UIInterfaceOrientation doesn't affect the transform, bounds, center, or frame properties directly. However, when the device orientation changes, the view controller will automatically resize its subview (which will in-turn resize it's subviews and so on).
See Responding to Device Orientation Changes and View Controller View Resizing for more details.

Why is there an frame rectangle and an bounds rectangle in an UIView?

Well although it's late in the dark night, I don't get it why there are two different rectangles: frame and bounds.
Like I understand it, one single rectangle would have been just enough to do everything. Positioning the View itself relative to another coordinate system, and then clipping it's content to a specified size. What else would you do with two rectangles? And how do they interact with each other?
Does anyone have a good explanation? The one from the Apple docs with the kid holding the fruit is not very good for understanding.
Here's the cheatsheet:
frame is where the view is (with respect to the superview)
bounds is where the view is allowed to draw (with respect to itself)
Some more clarification:
If you are positioning the view in its superview, you almost always change the frame origin.
If you are clipping where the UIView is drawing, you almost always modify its bounds.
Note that you are allowed to have bounds that is bigger than the frame. That is, you can draw "outside the lines" of where you are.
Frame is in the superview's coordinate system, bounds is in the view's coordinate system. From my perspective, it is a convenience to have both. Frame seems to be the more useful of the two, unless there is some case I am unaware of where a subview can have a completely different coordinate system (e.g. pixels scaled differently) than the superview.
I've been having troubles with bounds lately and have done some experimentation. The bounds property does limit where a UIView can draw, but does not limit its subviews. The other thing bounds controls is touch event dispatching. A view will not, as far a I can tell, receive touch events that are outside its bounds. Furthermore, any subview that outside of the parent view's bounds will also not receive touch events. In these situations, you have to pretty meticulously update the bounds of the container view as the size and position of its subviews change. Everything will always draw fine (because subviews aren't clipped by the bounds of their parent) but touches won't be received.
(This really should be a reply to an earlier post, but since I can't reply yet, it's stuck here...)

Resources