How do I prevent a UIImage from being Moved outside of its UIImageView? - objective-c

I'm trying to create a photo based app and I want to be able to crop, rotate and move the image thats been taken. I've done those things already but the UIImage created moves around the whole UIViewController and I only want it to be moved around within its UIImageView. Could anyone suggest how I might go about trying this? I've tried a few way already but they don't seemed to have worked. Any suggestions would be really helpful. Thanks!
Update
I'm adding in my code to help better explain what I'm trying to do . I'm sorry for not doing this before.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
//the 'image' below is the UIImage, it has already been declared before hand
image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
//layoutOne is my UIView which holds my UIImageView and UIImage. all of those are declared in my .h file.
layoutOne = [[UIView alloc] initWithFrame:CGRectMake(95.0, 107.0, 578, 682)];
theImageView = [[UIImageView alloc] initWithFrame:[layoutOne frame]];
[theImageView setImage:image];
[layoutOne addSubview:theImageView];
UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(scale:)];
[pinchRecognizer setDelegate:self];
[layoutOne addGestureRecognizer:pinchRecognizer];
UIRotationGestureRecognizer *rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotate:)];
[rotationRecognizer setDelegate:self];
[layoutOne addGestureRecognizer:rotationRecognizer];
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(move:)];
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];
[panRecognizer setDelegate:self];
[layoutOne addGestureRecognizer:panRecognizer];
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapped:)];
[tapRecognizer setNumberOfTapsRequired:1];
[tapRecognizer setDelegate:self];
[layoutOne addGestureRecognizer:tapRecognizer];
[self.view addSubview:layoutOne];
}
I'm using Interface Builder to create my app and I'm also using the newest version of Xcode. Thought I'd also add this incase it helped. Thanks

I don't think you can move the image within the image view. What you can to is to create a UIView as the frame and move the image within the bounds of the frame. Below is the code snippet (iOS 5 with ARC) that I hope it helps.
#implementation ImageFrame
{
UIImageView *imageView;
CGPoint previousPoint;
}
- (id)initWithFrame:(CGRect)frame andImage:(UIImage *)image
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor greenColor];
self.clipsToBounds = YES;
imageView = [[UIImageView alloc] initWithImage:image];
}
return self;
}
- (void)layoutSubviews
{
[self addSubview:imageView];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
previousPoint = [[touches anyObject] locationInView:self];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self];
CGPoint movePoint = CGPointMake(location.x - previousPoint.x, location.y - previousPoint.y);
CGPoint newCenter = CGPointMake(imageView.center.x + movePoint.x, imageView.center.y + movePoint.y);
imageView.center = newCenter;
previousPoint = location;
}
#end

Not sure what your current setup is, but make sure your UIImageView clipsToBounds property is set to YES.
If this doesn't answer your question, try checking the answers to Cropping an UIImage, which sounds like it may be describing a similar problem.

Related

Touch method UIImageView inside UIScrollView

I am wondering how I can use a touch method for a UIImageView inside a UIScrollView in xCode.
When I add the UIImageView subview to the self.view, I can use the touch method. But when I add the UIImageView subview to the UIScrollView, I can't. How can I solve this?
This is my code:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
touches = [event allTouches];
for (UITouch *touch in touches) {
NSLog(#"Image Touched");
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 44, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height * 0.9)];
scrollView.scrollEnabled = TRUE;
scrollView.bounces = TRUE;
scrollView.contentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
scrollView.userInteractionEnabled = YES;
[self.view addSubview:scrollView];
UIImageView *ImageView = [UIImageView alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width * 0.04, 10, [UIScreen mainScreen].bounds.size.width * 0.28, [UIScreen mainScreen].bounds.size.height * 0.22)];
ImageView.image = [UIImage imageNamed(#"image.png")];
ImageView.layer.borderColor = [UIColor whiteColor].CGColor;
ImageView.layer.borderWidth = 1;
ImageView.userInteractionEnabled = YES;
[scrollView addSubview:ImageView];
}
Give UIGestureRecognizers a try. They are far easier to manage with multiple layers of touch management.
- (void)touchedImage:(UITapGestureRecognizer *)gesture {
// When the gesture has ended, perform your action.
if (gesture.state == UIGestureRecognizerStateEnded) {
NSLog(#"Touched Image");
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 44, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height * 0.9)];
scrollView.scrollEnabled = TRUE;
scrollView.bounces = TRUE;
scrollView.contentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
scrollView.userInteractionEnabled = YES;
[self.view addSubview:scrollView];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width * 0.04, 10, [UIScreen mainScreen].bounds.size.width * 0.28, [UIScreen mainScreen].bounds.size.height * 0.22)];
imageView.image = [UIImage imageNamed:#"image.png"];
imageView.layer.borderColor = [UIColor whiteColor].CGColor;
imageView.layer.borderWidth = 1;
imageView.userInteractionEnabled = YES;
[scrollView addSubview:imageView];
// Create a tap gesture
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(touchedImage:)];
[imageView addGestureRecognizer:tap];
}
if you're dealing with multiple imageviews using the same gesture recognizer, it won't work. Try using a new gesture recognizer per image view.
User interaction of UIImageView is disabled by default you can enable it by setting imageView.userInteractionEnabled = YES;
You'll have to derive a CustomScrollView from UIScrollView and override all touches method like touchesBegan,Moved,Ended and Cancelled like below:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UIView *view in self.subviews)
{
UITouch *touch = [touches anyObject];
CGPoint pt = [touch locationInView:view];
if (CGRectContainsPoint(view.frame, pt))
{
[view touchesMoved:touches withEvent:event];
}
}
}
After you do this. When you add any view in the instance of customScrollView, you'll get the touches in the added view properly.
I had the same problem with an image view as a subview in a scroll view when applying a transformation.
Upon scroll my gesture recognizer no longer worked so I checked the offset of the scroll view and reset my image so the gesture was recognized.
And of course we need to set userInterActionEnabled to true and add the gesture in viewDidLoad()
override func viewDidLoad() {
imageView.userInteractionEnabled = true
addGesture()
}
func addGesture(){
let singleTap = UITapGestureRecognizer(target: self, action: #selector(MyViewController.enableGesture(_:)));
singleTap.numberOfTapsRequired = 1
self.imageView.addGestureRecognizer(singleTap)
self.imageView.tag = 1
}
override func scrollViewDidScroll(scrollView: UIScrollView) {
let offset = scrollView.contentOffset.y
if offset > 0 {
imageView.layer.transform = avatarTransform
}
else {
imageView.transform = CGAffineTransformIdentity
}
}

Gesture recognizer on multiple UIImageView

I have 10 UIImageViews in the same ViewController, and each one of these images need to be controlled with a Gesture Recognizer; this is my simple code:
- (void)viewDidLoad {
UIImageView *image1 = // image init
UIImageView *image2 = // image init
...
UIRotationGestureRecognizer *rotationGesture1 = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotatePiece:)];
UIRotationGestureRecognizer *rotationGesture2 = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotatePiece:)];
...
...
UIRotationGestureRecognizer *rotationGesture10 = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotatePiece:)];
[image1 addGestureRecognizer:rotationGesture1];
[image2 addGestureRecognizer:rotationGesture2];
...
...
[image10 addGestureRecognizer:rotationGesture10];
}
- (void)rotatePiece:(UIRotationGestureRecognizer *)gestureRecognizer {
if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) {
[gestureRecognizer view].transform = CGAffineTransformRotate([[gestureRecognizer view] transform], [gestureRecognizer rotation]);
[gestureRecognizer setRotation:0];
}
}
Ok, all right, each image rotates, but I need to write similar code also for UIPanGestureRecognizer and UIPinchGestureRecognizer, obv for each UIImageView: is this the correct way, or there is a simpler method to avoid "redundant" code like this? Thanks!
Here's a possible solution. Make a method like so:
- (void)addRotationGestureForImage:(UIImageView *)image
{
UIRotationGestureRecognizer *gesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotatePiece:)];
gesture.delegate = self;
[image addGestureRecognizer:gesture];
}
Then in your viewDidLoad method create an array of image views and loop through them calling this method like so:
NSArray *imageViewArray = [NSArray arrayWithObjects:image1,image2,image3,nil];
for(UIImageView *img in imageViewArray) {
[self addRotationGestureForImage:img];
}

UIImageView subclass doesn't work simultaneously gesture

I'm developing a iOs 6 app for iPad. I've developed a UIImageView subclass adding gesture recognizing (zoom, pinch and pan), but I've a problem: it doesn't admit simultaneously gestures. I first code it as a normal UIImageView, and it worked great, but now with the subclass it doesn't. My code:
image.m (UIImageView subclass)
- (id)initWithImage:(UIImage *)image {
self = [super initWithImage:image];
if (self) {
[self setMultipleTouchEnabled:YES];
[self setUserInteractionEnabled:YES];
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panDetected:)];
[super addGestureRecognizer:panRecognizer];
UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(pinchDetected:)];
[super addGestureRecognizer:pinchRecognizer];
UIRotationGestureRecognizer *rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotationDetected:)];
[super addGestureRecognizer:rotationRecognizer];
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapDetected:)];
tapRecognizer.numberOfTapsRequired = 2;
[super addGestureRecognizer:tapRecognizer];
NSLog(#"lkjlkj");
}
return self;}
- (void)panDetected:(UIPanGestureRecognizer *)panRecognizer {
CGPoint translation = [panRecognizer translationInView:self.superview];
CGPoint imageViewPosition = self.center;
imageViewPosition.x += translation.x;
imageViewPosition.y += translation.y;
self.center = imageViewPosition;
[panRecognizer setTranslation:CGPointZero inView: self.superview];}
- (void)pinchDetected:(UIPinchGestureRecognizer *)pinchRecognizer{
CGFloat scale = pinchRecognizer.scale;
self.transform = CGAffineTransformScale(self.transform, scale, scale);
pinchRecognizer.scale = 1.0;}
- (void)rotationDetected:(UIRotationGestureRecognizer *)rotationRecognizer{
CGFloat angle = rotationRecognizer.rotation;
self.transform = CGAffineTransformRotate(self.transform, angle);
rotationRecognizer.rotation = 0.0;}
- (void)tapDetected:(UITapGestureRecognizer *)tapRecognizer{
[UIView animateWithDuration:0.25 animations:^{
self.center = CGPointMake(CGRectGetMidX(self.superview.bounds), CGRectGetMidY(self.superview.bounds));
self.transform = CGAffineTransformIdentity;
}];}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;}
viewcontroller.m (where I create a imageview from image which doesn't respond to multiple gestures simultaneously)
image *img = [[image alloc] initWithImage:imatgetemporal];
img.center = CGPointMake(525/2, 651/2);
[[self.view viewWithTag:2] addSubview:img];
Thanks for all!!
I guess you can solve it by adding the same delegate to the UIPanGestureRecognizer, UIPinchGestureRecognizer, UIRotationGestureRecognizer and to the UITapGestureRecognizer just after declaring them. The code would be like this:
tapRecognizer.delegate = self;
pinchRecognizer.delegate = self;
rotationRecognizer.delegate = self;
tapRecognizer.delegate = self;
Hope it helps.

Losing Gesture Recognizers in UIPopoverController

I have a class called PhotoBoothController that I use to manipulate an image using gestures. It works fine when I run it on iPhone. However when I run it on iPad, I display the PhotoBoothController inside a UIPopoverController. The image appears fine, however I can't manipulate it as my gestures don't appear to be recognized. I'm not sure how to make the UIPopoverController take control of the gestures.
I present the popovercontroller and configure the view thus:
- (void)presentPhotoBoothForPhoto:(UIImage *)photo button:(UIButton *)button {
//Create a photoBooth and set its contents
PhotoBoothController *photoBoothController = [[PhotoBoothController alloc] init];
photoBoothController.photoImage.image = [button backgroundImageForState:UIControlStateNormal];
//set up all the elements programmatically.
photoBoothController.view.backgroundColor = [UIColor whiteColor];
//Add frame (static)
UIImage *frame = [[UIImage imageNamed:#"HumptyLine1Frame.png"] adjustForResolution];
UIImageView *frameView = [[UIImageView alloc] initWithImage:frame];
frameView.frame = CGRectMake(50, 50, frame.size.width, frame.size.height);
[photoBoothController.view addSubview:frameView];
//Configure image
UIImageView *photoView = [[UIImageView alloc] initWithImage:photo];
photoView.frame = CGRectMake(50, 50, photo.size.width, photo.size.height);
photoBoothController.photoImage = photoView;
//Add canvas
UIView *canvas = [[UIView alloc] initWithFrame:frameView.frame];
photoBoothController.canvas = canvas;
[canvas addSubview:photoView];
[canvas becomeFirstResponder];
[photoBoothController.view addSubview:canvas];
[photoBoothController.view bringSubviewToFront:frameView];
//resize the popover view shown in the current view to the view's size
photoBoothController.contentSizeForViewInPopover = CGSizeMake(frameView.frame.size.width+100, frameView.frame.size.height+400);
self.photoBooth = [[UIPopoverController alloc] initWithContentViewController:photoBoothController];
[self.photoBooth presentPopoverFromRect:button.frame
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
I thought [canvas becomeFirstResponder] might do it but it doesn't appear to make a difference.
Any advice much appreciate, thank you.
UPDATE: adding code as per comment
- (void)viewDidLoad {
[super viewDidLoad];
if (!_marque) {
_marque = [CAShapeLayer layer];
_marque.fillColor = [[UIColor clearColor] CGColor];
_marque.strokeColor = [[UIColor grayColor] CGColor];
_marque.lineWidth = 1.0f;
_marque.lineJoin = kCALineJoinRound;
_marque.lineDashPattern = [NSArray arrayWithObjects:[NSNumber numberWithInt:10],[NSNumber numberWithInt:5], nil];
_marque.bounds = CGRectMake(photoImage.frame.origin.x, photoImage.frame.origin.y, 0, 0);
_marque.position = CGPointMake(photoImage.frame.origin.x + canvas.frame.origin.x, photoImage.frame.origin.y + canvas.frame.origin.y);
}
[[self.view layer] addSublayer:_marque];
UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(scale:)];
[pinchRecognizer setDelegate:self];
[self.view addGestureRecognizer:pinchRecognizer];
UIRotationGestureRecognizer *rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotate:)];
[rotationRecognizer setDelegate:self];
[self.view addGestureRecognizer:rotationRecognizer];
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(move:)];
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];
[panRecognizer setDelegate:self];
[canvas addGestureRecognizer:panRecognizer];
UITapGestureRecognizer *tapProfileImageRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapped:)];
[tapProfileImageRecognizer setNumberOfTapsRequired:1];
[tapProfileImageRecognizer setDelegate:self];
[canvas addGestureRecognizer:tapProfileImageRecognizer];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return ![gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && ![gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]];
}
I am working on a similar application, and i can easily manipulate images on the canvas.
1) Check if the userInteractionEnabled property of the canvas is set to YES.
2) You can try adding the gestures to the ImageView's rather than the canvas. (I am guessing u want to zoom , rotate n swipe the images).
some guesses:
is this because viewDidLoad method have been called before cavas property been set? In this case, you could try to add recognizers after present popover in another method such as viewDidAppear.
I also agree that the key may be that UIPopoverController allows interaction to other views outside of the popover. So i suggest to move [canvas becomeFirstResponder]; to the end of the viewDidLoad method in PhotoBoothController and try self.view becomeFirstResponder here because you actually add recognizers to self.view.

location different CGPoint

Hi
how do I locate both the cgpoint? he gives me just one.
-(void)gestureLoad {
//GESTURE
UIGestureRecognizer *recognizer;
recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(numTap2:)];
[(UITapGestureRecognizer *)recognizer setNumberOfTouchesRequired:2];
[self.view addGestureRecognizer:recognizer];
self.tapRecognizer = (UITapGestureRecognizer *)recognizer;
recognizer.delegate = self;
[recognizer release];
}
- (void)numTap2:(UITapGestureRecognizer *)recognizer {
CGPoint location = [recognizer locationInView:self.view];
...other actions...
}
thanks a lot!
From the description of -[UIGestureRecognizer numberOfTouches]:
Using the value returned by this
method in a loop, you can ask for the
location of individual touches using
the locationOfTouch:inView: method.
So, call -locationOfTouche:inView: for each touch to get the corresponding location.