UIView-SubviewGeometry.h
#import <UIKit/UIKit.h>
@interface UIView (SubviewGeometry)
// Test whether view fits in its superview at a given center point
- (BOOL) canMoveToCenter: (CGPoint) aCenter inView: (UIView *) aView withInsets: (UIEdgeInsets) insets;
- (BOOL) canMoveToCenter: (CGPoint) aCenter inView: (UIView *) aView withInset: (float) inset;
- (BOOL) canMoveToCenter: (CGPoint) aCenter inView: (UIView *) aView;
// Slide view within superview using percents, e.g. 50% horizontal, 60% vertical
// View is guaranteed to fit within the parent.
- (CGPoint) centerInView: (UIView *) aView withHorizontalPercent: (float) h withVerticalPercent: (float) v;
- (CGPoint) centerInSuperviewWithHorizontalPercent: (float) h withVerticalPercent: (float) v;
// Move to a random point in the parent view, where child is guaranteed to
// fit inside the parent, and if specified, within an inset
- (CGPoint) randomCenterInView: (UIView *) aView withInsets: (UIEdgeInsets) insets;
- (CGPoint) randomCenterInView: (UIView *) aView withInset: (float) inset;
// Animate the movement to a random point within a particular view or the superview
// The child view is guaranteed to fit fully within the superview
- (void) moveToRandomLocationInView: (UIView *) aView animated: (BOOL) animated;
- (void) moveToRandomLocationInSuperviewAnimated: (BOOL) animated;
@end
UIView-SubviewGeometry.m
#import "UIView-SubviewGeometry.h"
CGRect rectWithCenter(CGRect rect, CGPoint center)
{
CGRect newrect = CGRectZero;
newrect.origin.x = center.x-CGRectGetMaxX(rect);
newrect.origin.y = center.y-CGRectGetMaxY(rect);
newrect.size = rect.size;
return newrect;
}
@implementation UIView (SubviewGeometry)
#pragma mark Bounded Placement
- (BOOL) canMoveToCenter: (CGPoint) aCenter inView: (UIView *) aView withInsets: (UIEdgeInsets) insets
{
CGRect container = UIEdgeInsetsInsetRect(aView.bounds, insets);
return CGRectContainsRect(container, rectWithCenter(self.frame, aCenter));
}
- (BOOL) canMoveToCenter: (CGPoint) aCenter inView: (UIView *) aView withInset: (float) inset
{
UIEdgeInsets insets = UIEdgeInsetsMake(inset, inset, inset, inset);
return [self canMoveToCenter:aCenter inView:aView withInsets:insets];
}
- (BOOL) canMoveToCenter: (CGPoint) aCenter inView: (UIView *) aView
{
return [self canMoveToCenter:aCenter inView:aView withInset:0];
}
#pragma mark Percent Displacement
// Move view into place as a percentage-based displacement
- (CGPoint) centerInView: (UIView *) aView withHorizontalPercent: (float) h withVerticalPercent: (float) v
{
// Move in by the inset amount and then by size of the subview
CGRect baseRect = aView.bounds;
CGRect subRect = CGRectInset(baseRect, self.frame.size.width / 2.0f, self.frame.size.height /2.0f);
// Return a point that is h% horizontal and v% vertical
float px = (float)(h * subRect.size.width);
float py = (float)(v * subRect.size.height);
return CGPointMake(px + subRect.origin.x, py + subRect.origin.y);
}
- (CGPoint) centerInSuperviewWithHorizontalPercent: (float) h withVerticalPercent: (float) v
{
return [self centerInView:self.superview withHorizontalPercent:h withVerticalPercent:v];
}
#pragma mark Random
// Make sure you've run srandom() elsewhere in the program
// Thanks to August Joki and manitoba98
- (CGPoint) randomCenterInView: (UIView *) aView withInsets: (UIEdgeInsets) insets
{
// Move in by the inset amount and then by size of the subview
CGRect innerRect = UIEdgeInsetsInsetRect([aView bounds], insets);
CGRect subRect = CGRectInset(innerRect, self.frame.size.width / 2.0f, self.frame.size.height/ 2.0f);
// Return a random point
float rx = (float)(random() % (int)floor(subRect.size.width));
float ry = (float)(random() % (int)floor(subRect.size.height));
return CGPointMake(rx + subRect.origin.x, ry + subRect.origin.y);
}
- (CGPoint) randomCenterInView: (UIView *) aView withInset: (float) inset
{
UIEdgeInsets insets = UIEdgeInsetsMake(inset, inset, inset, inset);
return [self randomCenterInView:aView withInsets:insets];
}
- (void) moveToRandomLocationInView: (UIView *) aView animated: (BOOL) animated
{
if (!animated)
{
self.center = [self randomCenterInView:aView withInset:5];
return;
}
// Why 0.3f seconds? Because that is the time used to display a keyboard
CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.3f];
self.center = [self randomCenterInView:aView withInset:5];
[UIView commitAnimations];
}
- (void) moveToRandomLocationInSuperviewAnimated: (BOOL) animated
{
[self moveToRandomLocationInView:self.superview animated:animated];
}
@end
#import <UIKit/UIKit.h>
#import "UIView-SubviewGeometry.h"
#define COOKBOOK_PURPLE_COLOR [UIColor colorWithRed:0.20392f green:0.19607f blue:0.61176falpha:1.0f]
#define BARBUTTON(TITLE, SELECTOR) [[[UIBarButtonItem alloc] initWithTitle:TITLE style:UIBarButtonItemStylePlain target:self action:SELECTOR] autorelease]
@interface TestBedViewController : UIViewController
{
NSTimer *timer;
}
@end
@implementation TestBedViewController
-(void) move: (NSTimer *) aTimer
{
[[self.view viewWithTag:999] moveToRandomLocationInSuperviewAnimated:YES];
}
-(void) start: (id) sender
{
timer = [NSTimer scheduledTimerWithTimeInterval:0.5f target:self selector:@selector(move:)userInfo:nil repeats:YES];
[self move:nil];
self.navigationItem.rightBarButtonItem = BARBUTTON(@"stop", @selector(stop:));
}
-(void) stop: (id) sender
{
[timer invalidate];
timer = nil;
self.navigationItem.rightBarButtonItem = BARBUTTON(@"start", @selector(start:));
}
-(void) viewDidLoad
{
self.navigationController.navigationBar.tintColor = COOKBOOK_PURPLE_COLOR;
self.navigationItem.rightBarButtonItem = BARBUTTON(@"start", @selector(start:));
UIView *outerView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 240.0f, 240.f)];
outerView.center = CGPointMake(160.0f, 140.0f);
outerView.backgroundColor = [UIColor lightGrayColor];
outerView.tag = 998;
[self.view addSubview:outerView];
[outerView release];
UIView *innerView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 80.0f, 80.0f)];
innerView.backgroundColor = COOKBOOK_PURPLE_COLOR;
innerView.tag = 999;
[outerView addSubview:innerView];
[innerView release];
timer = nil;
}
@end
@interface TestBedAppDelegate : NSObject <UIAlertViewDelegate>
@end
@implementation TestBedAppDelegate
-(void)applicationDidFinishLaunching:(UIApplication *)application
{
UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[[TestBedViewController alloc] init]];
[window addSubview:nav.view];
[window makeKeyAndVisible];
}
//- (void)applicationDidFinishLaunching:(UIApplication *)application {
// UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[[TestBedViewController alloc] init]];
// [window addSubview:nav.view];
// [window makeKeyAndVisible];
//}
@end
int main(int argc, char *argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, @"TestBedAppDelegate");
[pool release];
return retVal;
}