I personally suspect the holderView
logic. You're adding holderView
to your controller's top level view using the vertical offset of i * 30
, but when you're adding the imageView
to the holderView
, you're offsetting it within holderView
by i * 30
again (because you're using the frame
of holderView
, which has a y
offset in it)! Worse, because your gesture recognizer is on the holderView
and not the imageView
, when you try to grab the imageView
by tapping on the image, you're often going to not be over the holderView
you thought you were, but rather one for one of the other images!
Assuming you like the way the images are laid out right now (really 60.0 points apart), then I'd suggest you change that i*30
to i*60.0
and either:
change the setting of
frame
for theimageView
to[holderView bounds]
; or, even better,get rid of the
holderView
views altogether because (at least on the basis of what you've shared so far) it adds no value and only complicates the code.
As an aside, a few other observations:
The
images
array doesn't need to be mutable, and you shouldn't be reinitializing it inside thefor
loop.You probably should reference
[images count]
rather than hard coding4
in yourfor
loop.
With these changes, the viewDidLoad
code then looks like:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSArray *images = [[NSArray alloc]initWithObjects:@"iphone-status-bar.png",@"uiswitch.png",@"NavigationBar.png",@"barbutton.png",@"ios-back-button.png", nil];
// if you're using a recent version of the compiler, you could simplify that further to just
//
// NSArray *images = @[@"iphone-status-bar.png",@"uiswitch.png",@"NavigationBar.png",@"barbutton.png",@"ios-back-button.png"];
for (int i = 0; i < [images count]; i++) {
NSString *imageName = [images objectAtIndex:i]; // or you could say `NSString *imageName = images[i];`
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(2.0, i * 60.0, image.size.width, image.size.height);
imageView.userInteractionEnabled = YES;
[self.view addSubview:imageView];
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(move:)];
panRecognizer.minimumNumberOfTouches = 1;
panRecognizer.maximumNumberOfTouches = 1;
[imageView addGestureRecognizer:panRecognizer];
}
}
You can simplify your move
routine a bit, too:
-(void)move:(UIPanGestureRecognizer *)gesture {
static CGPoint originalCenter; // or make this a class ivar; but don't make this a global!
if (gesture.state == UIGestureRecognizerStateBegan) {
[gesture.view.superview bringSubviewToFront:gesture.view];
originalCenter = gesture.view.center;
}
CGPoint translation = [gesture translationInView:self.view];
CGPoint translatedPoint = CGPointMake(originalCenter.x+translation.x, originalCenter.y+translation.y);
gesture.view.center = translatedPoint;
if(gesture.state == UIGestureRecognizerStateEnded) {
CGPoint velocity = [gesture velocityInView:gesture.view];
translatedPoint.x = MAX(translatedPoint.x + .01 * velocity.x, 0.0);
translatedPoint.y = MAX(translatedPoint.y + .01 * velocity.y, 0.0);
if(UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation])) {
translatedPoint.x = MIN(translatedPoint.x, 768.0);
translatedPoint.y = MIN(translatedPoint.y, 1024.0);
}
else {
translatedPoint.x = MIN(translatedPoint.x, 1024.0);
translatedPoint.y = MIN(translatedPoint.y, 768.0);
}
[UIView animateWithDuration:0.35
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
gesture.view.center = translatedPoint;
}
completion:nil];
}
}
Personally, I hate seeing hard-coded coordinates, so I might further simplify the UIGestureRecognizerStateEnded
code to something like:
if(gesture.state == UIGestureRecognizerStateEnded) {
CGPoint velocity = [gesture velocityInView:gesture.view];
translatedPoint.x = MAX(translatedPoint.x + .01 * velocity.x, 0.0);
translatedPoint.y = MAX(translatedPoint.y + .01 * velocity.y, 0.0);
translatedPoint.x = MIN(translatedPoint.x, gesture.view.superview.bounds.size.width);
translatedPoint.y = MIN(translatedPoint.y, gesture.view.superview.bounds.size.height);
[UIView animateWithDuration:0.35
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
gesture.view.center = translatedPoint;
}
completion:nil];
}