Problem
You want to specify collision boundaries between your UI
components on the screen so that they will not overlap one another.
Solution
Instantiate an object of type UICollisionBehavior and attach it
to your animator ob‐ ject. Set the translatesReferenceBoundsIntoBoundary
property of your collision be‐havior to YES and ensure that your animator is
initialized with your superview as its reference value. This will ensure that
the subviews that are the targets of your collision behavior (as will be
discussed soon) will not go outside the boundaries of your super‐ view.
Discussion
A collision behavior of type UICollisionBehavior takes in
objects that conform to the UIDynamicItem protocol. All views of type UIView
already conform to this protocol, so all you have to do is instantiate your
views and add them to the collision behavior. A collision behavior requires you
to define the boundaries that the items in the animator will not be able to go
past. For instance, if you define a line that runs from the bottom- left edge to
the bottom-right edge of your reference view (the bottommost horizontal line of
your reference view), and add a gravity behavior to your view as well, those
views will be pulled down by gravity to the bottom of the view but will not be
able to go further because they will collide with the bottom edge of the view,
defined by the collision behavior.
If you want your reference view’s boundaries to be considered as
the boundaries of your collision detection behavior, just set the
translatesReferenceBoundsIntoBoundary property of the collision behavior’s
instance to YES. If you want to add custom lines as boundaries to your collision
behavior, simply use the addBoundaryWithIdentifi er:fromPoint:toPoint: instance
method of the UICollisionBehavior class.
In this recipe, we are going to create two colored views, one on
top of the other, and then add gravity to our animator so that the views will
fall down from the center of the view controller’s view. Then we are going to
add a collision behavior to the mix so that the views will not overlap each
other. In addition, they won’t go outside the boundaries of the reference view
(the view controller’s view).
So let’s begin by defining an array of our views and our
animator:
#import "ViewController.h"
@interface ViewController
()?
@property (nonatomic, strong) NSMutableArray
*squareViews;
@property (nonatomic, strong) UIDynamicAnimator
*animator;
@end
Then when our view appears on the screen, we will set up the
collision and the gravity behaviors and add them to an animator:
-
(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
/* Create the
views */
NSUInteger const NumberOfViews = 2;?
self.squareViews = [[NSMutableArray alloc]
initWithCapacity:NumberOfViews];
NSArray *colors = @[[UIColor redColor], [UIColor
greenColor]];
CGPoint currentCenterPoint = self.view.center;?
CGSize eachViewSize = CGSizeMake(50.0f, 50.0f);
?for (NSUInteger counter = 0; counter <
NumberOfViews; counter++){
UIView *newView =
[[UIView alloc] initWithFrame:
CGRectMake(0.0f, 0.0f, eachViewSize.width, eachViewSize.height)];
newView.backgroundColor = colors[counter];
newView.center = currentCenterPoint;
currentCenterPoint.y += eachViewSize.height + 10.0f;
[self.view addSubview:newView];
[self.squareViews addObject:newView];
}
self.animator =
[[UIDynamicAnimator alloc]
initWithReferenceView:self.view];
/* Create gravity
*/
UIGravityBehavior *gravity = [[UIGravityBehavior
alloc]
initWithItems:self.squareViews];
[self.animator
addBehavior:gravity];
/* Create
collision detection */
UICollisionBehavior
*collision = [[UICollisionBehavior alloc]
initWithItems:self.squareViews];
collision.translatesReferenceBoundsIntoBoundary = YES;
[self.animator
addBehavior:collision];
}
Detecting and reacting to collisions Between UI
Components