0

To describe my project:

I have a rectangle UIImageView frame floating over a white layer. Inside the UIImageView, I'm successfully creating the illusion that it is showing a portion of a background image behind the white layer. You can drag the rectangle around, and it will "redraw" the image so that you can peer into what is behind the white. Its basically this code:

//whenever the frame is moved, updated the CGRect frameRect and run this:

self.newCroppedImage = CGImageCreateWithImageInRect([bgImage.image CGImage], frameRect);
 frame.image = [UIImage imageWithCGImage:self.newCroppedImage];

Anyhow, I also have a rotation gesture recognizer that allows the user to rotate the frame (and consequentially rotates the image). This is because the CGRect sent to the CGImageCreateWithImageInRect is still oriented at its original rotation. This breaks the illusion that you're looking through a window because the image you see is rotated when only the frame should appear that way.

So ideally, I need to take the rotation of my frame and apply it to the image created from my bgImage. Does anyone have any clues or ideas on how I could apply this?

user339946
  • 5,961
  • 9
  • 52
  • 97

1 Answers1

4

I suggest you take a different approach. Don't constantly create new images to put in your UIImageView. Instead, set up your view hierarchy like this:

White view
    "Hole" view (just a regular UIView)
        Image view

That is, the white view has the hole view as a subview. The hole view has the UIImageView as its subview.

The hole view must have its clipsToBounds property set to YES (you can set it with code or in your nib).

The image view should have its size set to the size of its image. This will of course be larger than the size of the hole view.

And this is very very important: the image view's center must be set to the hole view's center.

Here's the code I used in my test project to set things up. The white view is self.view. I start with the hole centered in the white view, and I set the image view's center to the hole view's center.

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:YES];

    CGRect bounds = self.view.bounds;
    self.holeView.center = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
    self.holeView.clipsToBounds = YES;

    bounds = self.holeView.bounds;
    self.imageView.center = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
    self.imageView.bounds = (CGRect){ CGPointZero, self.imageView.image.size };

}

I also set the image view's size to the size of its image. You might want to set it to the size of the white view.

To pan and rotate the hole, I'm going to set holeView.transform. I'm not going to change holeView.frame or holeView.center. I have two instance variables, _holeOffset and _holeRotation, that I use to compute the transform. The trick to making it seem like a hole through the white view, revealing the image view, is to apply the inverse transform to the image view, undoing the effects of the hole view's transform:

- (void)updateTransforms {
    CGAffineTransform holeTransform = CGAffineTransformIdentity;
    holeTransform = CGAffineTransformTranslate(holeTransform, _holeOffset.x, _holeOffset.y);
    holeTransform = CGAffineTransformRotate(holeTransform, _holeRotation);
    self.holeView.transform = holeTransform;
    self.imageView.transform = CGAffineTransformInvert(holeTransform);
}

This trick of using the inverse transform on the subview only works if the center of the subview is at the center of its superview. (Technically the anchor points have to line up, but by default the anchor point of a view is its center.)

I put a UIPanGestureRecognizer on holeView. I configured it to send panGesture: to my view controller:

- (IBAction)panGesture:(UIPanGestureRecognizer *)sender {
    CGPoint offset = [sender translationInView:self.view];
    [sender setTranslation:CGPointZero inView:self.view];
    _holeOffset.x += offset.x;
    _holeOffset.y += offset.y;
    [self updateTransforms];
}

I also put a UIRotationGestureRecognizer on holeView. I configured it to send rotationGesture: to my view controller:

- (IBAction)rotationGesture:(UIRotationGestureRecognizer *)sender {
    _holeRotation += sender.rotation;
    sender.rotation = 0;
    [self updateTransforms];
}
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • Thank you, this code is amazing. I have it working in my xcode. I haven't fully digested it yet as its late where I am, but this achieves exactly what I sought out to do. – user339946 Jan 15 '12 at 09:42