UIScrollView zoomed with subviews gets different position after back from background - ios

All,
I have a viewController with a ScrollView. On this scrollView, I have a UIImage as subview.
UIImage *image = [UIImage imageNamed:#"greyblue_numbered_15x15_900x900.png"];
self.boardImage = [[UIImageView alloc] initWithImage:image];
self.boardImage.frame = (CGRect){.origin=CGPointMake(0.0f, 0.0f), .size=image.size};
[self.boardScrollView addSubview:self.boardImage];
self.boardScrollView.contentSize = image.size;
When I zoom, use home button and then call app again, everything is fine.
Now, I place an other subview on it by dragging the object to the scrollView:
- (void)myTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint touchPointScreen = [[touches anyObject] locationInView:self.view];
CGPoint touchPointImage = [[touches anyObject] locationInView:self.boardImage];
if (touchPointScreen.x > self.boardScrollView.frame.origin.x &&
touchPointScreen.x < self.boardScrollView.frame.origin.x + self.boardScrollView.frame.size.width &&
touchPointScreen.y > self.boardScrollView.frame.origin.y &&
touchPointScreen.y < self.boardScrollView.frame.origin.y + self.boardScrollView.frame.size.height)
{
self.tmpDragObject.frame = CGRectMake(x,y,60,60);
[self.boardImage addSubview:self.tmpDragObject];
}
self.tmpDragObject = nil;
}
When I zoom, the subviews are also zoomed.
- (void)scrollViewDoubleTapped:(UITapGestureRecognizer*)recognizer {
CGPoint pointInView = [recognizer locationInView:self.boardScrollView];
CGFloat newZoomScale = self.boardScrollView.zoomScale * 1.5f;
newZoomScale = MIN(newZoomScale, self.boardScrollView.maximumZoomScale);
if (newZoomScale != 1.0f) {
CGSize scrollViewSize = self.boardScrollView.bounds.size;
CGFloat w = scrollViewSize.width / newZoomScale;
CGFloat h = scrollViewSize.height / newZoomScale;
CGFloat x = pointInView.x - (w / 2.0f);
CGFloat y = pointInView.y - (h / 2.0f);
CGRect rectToZoomTo = CGRectMake(x, y, w, h);
[self.boardScrollView zoomToRect:rectToZoomTo animated:YES];
}
ISSUE: When I use the home button and then call the app again, the app repositions the subviews of the ScrollView. So all subviews are replaced downwards, about the size of the tmpDragObject or the size of the navigation bar.
Why is this happening? And how can I fix this?

Apparently, I had to set the automaticallyAdjustsScrollViewInsets on my view controller to NO.

Related

How to pinch google map when it set in UIScrollView in iOS Objective C

I set Google Map in view in UIScrollView. everything OK but i can not pinch my map. How to fix it?
Salaam Reza jaan.
In your case you can use something like this. Cheers.
Edit: this is a better way to do it. Behbakht shid, direh inja :P
- (void) scaleSelfWith:(UIPinchGestureRecognizer *)gestureRecognizer{
if ([gestureRecognizer numberOfTouches] >1) {
//getting width and height between gestureCenter and one of my finger
float x = [gestureRecognizer locationInView:self].x - [gestureRecognizer locationOfTouch:1 inView:self].x;
if (x<0) {
x *= -1;
}
float y = [gestureRecognizer locationInView:self].y - [gestureRecognizer locationOfTouch:1 inView:self].y;
if (y<0) {
y *= -1;
}
//set Border
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
xDis = self.bounds.size.width - x*2;
yDis = self.bounds.size.height - y*2;
}
//double size cause x and y is just the way from the middle to my finger
float width = x*2+xDis;
if (width < 1) {
width = 1;
}
float height = y*2+yDis;
if (height < 1) {
height = 1;
}
self.bounds = CGRectMake(self.bounds.origin.x , self.bounds.origin.y , width, height);
[gestureRecognizer setScale:1];
[[self layer] setBorderWidth:2.f];
}
}

Zoom a specific area of a Scrollview

I'm stuck on a case where I want to zooming a part(rect) of a scrollview programatically not by touch or gestures.
CGRect cropRect = CGRectMake(xPos * [UIScreen mainScreen].nativeScale, yPos * [UIScreen mainScreen].nativeScale, width1 * [UIScreen mainScreen].nativeScale, height1 * [UIScreen mainScreen].nativeScale);
[self.scrlVPhoto zoomToRect:cropRect animated:YES];
I've set delegate and also implemented delegate method.
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)aScrollView {
return self.containerView;
}
self.containerView is a view that I want to zoom.
I've tried everything and I'm still confused how to get out of this.
Please some one can help me. Any help is appreciated.
Thanks in advance.
I am going to answer my own question.
I've searched lots of articles and hours of debugging I've found that when scrollview is zoomed then actually its contentSize is increased its zoomScale remain unchanged.
So I just used transform property of the scrollview's subview (i.e. self.containerView) and set scrollview's contentOffset I got what I was looking for.
self.containerView.transform = CGAffineTransformMakeScale(1.8, 1.8); // containerView is subview of scrollview and 1.8 is zoom scale just for eg.
[self.scrlVPhoto setContentOffset:CGPointMake(self.scrlVPhoto.contentOffset.x, (self.scrlVPhoto.contentOffset.y + cropRect.origin.y)) animated:true];
You should add the view which you want to zoom inside the scrollview. Inside the delegate method return the view which you want to zoom.
I have Create the UIImageView, set the Zoom option in imageView when double tap or single tap to UIImageView and the code is given below,
viewDidLoad Method:
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleDoubleTap:)];
[doubleTap setNumberOfTapsRequired:2];
DoubleTab Method:
- (void)handleDoubleTap:(UIGestureRecognizer *)gestureRecognizer {
// zoom in
float newScale = [myscrollview zoomScale] * 2;
if (newScale > self.myscrollview.maximumZoomScale){
newScale = self.myscrollview.minimumZoomScale;
CGRect zoomRect = [self zoomRectForScale:newScale withCenter:[gestureRecognizer locationInView:gestureRecognizer.view]];
[myscrollview zoomToRect:zoomRect animated:YES];
}
else{
newScale = self.myscrollview.maximumZoomScale;
CGRect zoomRect = [self zoomRectForScale:newScale withCenter:[gestureRecognizer locationInView:gestureRecognizer.view]];
[myscrollview zoomToRect:zoomRect animated:YES];
}
}
- (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center {
CGRect zoomRect;
// the zoom rect is in the content view's coordinates.
// At a zoom scale of 1.0, it would be the size of the imageScrollView's bounds.
// As the zoom scale decreases, so more content is visible, the size of the rect grows.
zoomRect.size.height = [myscrollview frame].size.height / scale;
zoomRect.size.width = [myscrollview frame].size.width / scale;
// choose an origin so as to get the right center.
zoomRect.origin.x = center.x - (zoomRect.size.width / 2.0);
zoomRect.origin.y = center.y - (zoomRect.size.height / 2.0);
return zoomRect;
}
And you need the delegate methods are shown below,
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
if (vmov==nil)
{
float newwidth;
float newheight;
UIImage *image=detaimageview.image;
if (image.size.height>=image.size.width){
newheight=detaimageview.frame.size.height;
newwidth=(image.size.width/image.size.height)*newheight;
if(newwidth>detaimageview.frame.size.width){
float diff=detaimageview.frame.size.width-newwidth;
newheight=newheight+diff/newheight*newheight;
newwidth=detaimageview.frame.size.width;
}
}
else{
newwidth=detaimageview.frame.size.width;
newheight=(image.size.height/image.size.width)*newwidth;
if(newheight>detaimageview.frame.size.height){
float diff=detaimageview.frame.size.height-newheight;
newwidth=newwidth+diff/newwidth*newwidth;
newheight=detaimageview.frame.size.height;
myscrollview.clipsToBounds = NO;
}
}
CGRect frame;
CGFloat screenWidth;
CGFloat screenHeight;
CGRect screenRect = [[UIScreen mainScreen] bounds];
screenWidth = screenRect.size.width;
screenHeight = screenRect.size.height-64;
frame.size.width = newwidth;
frame.size.height = newheight;
self.myscrollview.contentSize = frame.size;
float x,y;
x=0;
y=0;
if (newheight<screenHeight)
{
x =screenHeight/2-newheight/2;
}
if (newwidth<screenWidth)
{
y =screenWidth/2-newwidth/2;
}
self.detaimageview.frame = CGRectMake(y,x,newwidth,newheight);
return self.detaimageview;
}
return nil;
}
this above codes are zoom the imageView and its working for my Projects,
hope its helpful
Please check this one. Its may be helpful to you
-(void)handlePinchWithGestureRecognizer:(UIPinchGestureRecognizer *)pinchGestureRecognizer{
//[self.superImage_View setAlpha:0.5];
if([pinchGestureRecognizer state] == UIGestureRecognizerStateBegan) {
// Reset the last scale, necessary if there are multiple objects with different scales
lastScale = [pinchGestureRecognizer scale];
}
if ([pinchGestureRecognizer state] == UIGestureRecognizerStateBegan ||
[pinchGestureRecognizer state] == UIGestureRecognizerStateChanged){
CGFloat currentScale = [[[pinchGestureRecognizer view].layer valueForKeyPath:#"transform.scale"] floatValue];
// Constants to adjust the max/min values of zoom
const CGFloat kMaxScale = 2.0;
const CGFloat kMinScale = 1.0;
CGFloat newScale = 1-(lastScale-[pinchGestureRecognizer scale]) ; // new scale is in the range (0-1)
newScale = MIN(newScale, kMaxScale / currentScale);
newScale = MAX(newScale, kMinScale / currentScale);
CGAffineTransform transform = CGAffineTransformScale([[pinchGestureRecognizer view] transform], newScale, newScale);
[pinchGestureRecognizer view].transform = transform;
lastScale = [pinchGestureRecognizer scale]; // Store the previous scale factor for the next pinch gesture call
}
if ([pinchGestureRecognizer state] == UIGestureRecognizerStateEnded) {
[undoList addObject:cropImage];
}
}

Setting the Min and Max width and height for resizable UIView

I wanted to make a resizable UIView using touches from corners, and I've found this answer here and it worked well. But how can I add the ability to stop resizing when the width/height is 200 for example?
This is the code:
CGFloat kResizeThumbSize = 45.0f;
#interface MY_CLASS_NAME : UIView {
BOOL isResizingLR;
BOOL isResizingUL;
BOOL isResizingUR;
BOOL isResizingLL;
CGPoint touchStart;
}
And..
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
touchStart = [[touches anyObject] locationInView:self];
isResizingLR = (self.bounds.size.width - touchStart.x < kResizeThumbSize && self.bounds.size.height - touchStart.y < kResizeThumbSize);
isResizingUL = (touchStart.x <kResizeThumbSize && touchStart.y <kResizeThumbSize);
isResizingUR = (self.bounds.size.width-touchStart.x < kResizeThumbSize && touchStart.y<kResizeThumbSize);
isResizingLL = (touchStart.x <kResizeThumbSize && self.bounds.size.height -touchStart.y <kResizeThumbSize);
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint touchPoint = [[touches anyObject] locationInView:self];
CGPoint previous = [[touches anyObject] previousLocationInView:self];
CGFloat deltaWidth = touchPoint.x - previous.x;
CGFloat deltaHeight = touchPoint.y - previous.y;
// get the frame values so we can calculate changes below
CGFloat x = self.frame.origin.x;
CGFloat y = self.frame.origin.y;
CGFloat width = self.frame.size.width;
CGFloat height = self.frame.size.height;
if (isResizingLR) {
self.frame = CGRectMake(x, y, touchPoint.x+deltaWidth, touchPoint.y+deltaWidth);
} else if (isResizingUL) {
self.frame = CGRectMake(x+deltaWidth, y+deltaHeight, width-deltaWidth, height-deltaHeight);
} else if (isResizingUR) {
self.frame = CGRectMake(x, y+deltaHeight, width+deltaWidth, height-deltaHeight);
} else if (isResizingLL) {
self.frame = CGRectMake(x+deltaWidth, y, width-deltaWidth, height+deltaHeight);
} else {
// not dragging from a corner -- move the view
self.center = CGPointMake(self.center.x + touchPoint.x - touchStart.x,
self.center.y + touchPoint.y - touchStart.y);
}
}
Thanks
if (isResizingLR) {
if(touchPoint.x+deltaWidth < 200 && touchPoint.y+deltaWidth < 200)
self.frame = CGRectMake(x, y, touchPoint.x+deltaWidth, touchPoint.y+deltaWidth);
} else if (isResizingUL) {
if(width-deltaWidth < 200 && height-deltaHeight < 200)
self.frame = CGRectMake(x+deltaWidth, y+deltaHeight, width-deltaWidth, height-deltaHeight);
} else if (isResizingUR) {
if(width+deltaWidth < 200 && height-deltaHeight < 200)
self.frame = CGRectMake(x, y+deltaHeight, width+deltaWidth, height-deltaHeight);
} else if (isResizingLL) {
if(width-deltaWidth < 200 && height+deltaHeight < 200)
self.frame = CGRectMake(x+deltaWidth, y, width-deltaWidth, height+deltaHeight);
}
This should work.
#property(nonatomic) CGRect frame
Description The frame rectangle, which describes the view’s location and size in its superview’s coordinate system.
Before setting self.frame with CGRect, check for width and height!
CGRect CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height);
Use width and height for actual size and delta for transformation.

How to add a Gesture Recogniser in imageview in iOS?

i add a UIPanGestureRecognizer to my imageview then Gesture Recognizer is added but my imageview image is panned in to my view i want only image is panned inside of the imageview on in the view how it is possible?
i write a code for that on viewdidload
UIPanGestureRecognizer *pangesture=[[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(panGestureDetected:)];
[pangesture setDelegate:self];
[self.zoomImage addGestureRecognizer:pangesture];
and method for that is
- (void)panGestureDetected:(UIPanGestureRecognizer *)recognizer
{
UIGestureRecognizerState state = [recognizer state];
if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
{
CGPoint translation = [recognizer translationInView:recognizer.view];
[recognizer.view setTransform:CGAffineTransformTranslate(recognizer.view.transform, translation.x, translation.y)];
[recognizer setTranslation:CGPointZero inView:recognizer.view];
}
}
then imageView image is panned in my View but i want image Panned only inside of imageview if it possible then give me solution.
here my original imageview Size is like as
and when i added UIPanGEstureRecognizer then it look like as
image are panned in View but i want to zoom it inside of imageview size please give me solution for that.
take UIScrollView and add UIImageView inside the scrollview and pangesture on scrollview ..
set delegate for scrollview and do the code
- (UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView {
// Return the view that we want to zoom
return self.zoomImage;
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
// The scroll view has zoomed, so we need to re-center the contents
[self centerScrollViewContents];
}
- (void)centerScrollViewContents {
CGSize boundsSize = scrollView.bounds.size;
CGRect contentsFrame = self.zoomImage.frame;
if (contentsFrame.size.width < boundsSize.width) {
contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2.0f;
} else {
contentsFrame.origin.x = 0.0f;
}
if (contentsFrame.size.height < boundsSize.height) {
contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0f;
} else {
contentsFrame.origin.y = 0.0f;
}
self.zoomImage.frame = contentsFrame;
}
- (void)scrollViewDoubleTapped:(UITapGestureRecognizer*)recognizer {
// Get the location within the image view where we tapped
CGPoint pointInView = [recognizer locationInView:imageView];
// Get a zoom scale that's zoomed in slightly, capped at the maximum zoom scale specified by the scroll view
CGFloat newZoomScale = scrollView.zoomScale * 1.5f;
newZoomScale = MIN(newZoomScale, scrollView.maximumZoomScale);
// Figure out the rect we want to zoom to, then zoom to it
CGSize scrollViewSize = scrollView.bounds.size;
CGFloat w = scrollViewSize.width / newZoomScale;
CGFloat h = scrollViewSize.height / newZoomScale;
CGFloat x = pointInView.x - (w / 2.0f);
CGFloat y = pointInView.y - (h / 2.0f);
CGRect rectToZoomTo = CGRectMake(x, y, w, h);
[scrollView zoomToRect:rectToZoomTo animated:YES];
}
- (void)scrollViewTwoFingerTapped:(UITapGestureRecognizer*)recognizer {
// Zoom out slightly, capping at the minimum zoom scale specified by the scroll view
CGFloat newZoomScale = scrollView.zoomScale / 1.5f;
newZoomScale = MAX(newZoomScale, scrollView.minimumZoomScale);
[scrollView setZoomScale:newZoomScale animated:YES];
}
UIImage object's userInteractEnable is NO by default, so you can't interact with it. Try self.zoomImage.userInteractEnable = YES
Try this:
Add another UIView under the imageView, make its size exactly the same as your imageView. Then set your imageView as this UIView's subview by drag and drop the imageView on top of this UIView (Assuming you are using StoryBoard or xib).
After that, if you are using StoryBoard or xib, then go to Attributes Inspector, select this UIView, tick Click Subviews. If not, just set view.clipsToBounds = YES;

Wrong touch point location in UIView after rotatation

I'm trying to make a custom button using a UIView and when touched on a specific part of the view perform an action, for example when touching the left part of the view log LEFT and when touching the Right part of the view log RIGHT.
I'm using touchesBegan and touchesEnded to detect touch.
Everything works fine when in portrait mode, however, once rotated to landscape mode it doesn't work, the view is displayed in the right place and the touch on the view is detected but it seems the touch point is not in the correct x,y coordinates so I can't detect the LEFT/RIGHT touches correctly.
Couldn't find any previous answers here that helped me.
Tried looking into CGAffineTransform, but still can't fix it.
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"round_directions_button_default.png"]];
self.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin;
topLeft = CGPointMake(self.frame.origin.x, self.frame.origin.y);
topRight = CGPointMake(self.frame.origin.x + 105, self.frame.origin.y);
bottomLeft = CGPointMake(self.frame.origin.x, self.frame.origin.y + 105);
bottomRight = CGPointMake(self.frame.origin.x + 105, self.frame.origin.y + 105);
NSLog(#"topLeft: x = %f, y = %f", topLeft.x, topLeft.y);
NSLog(#"topRight: x = %f, y = %f", topRight.x, topRight.y);
NSLog(#"bottomLeft: x = %f, y = %f", bottomLeft.x, bottomLeft.y);
NSLog(#"bottomRight: x = %f, y = %f", bottomRight.x, bottomRight.y);
NSLog(#"self.center: x = %f, y = %f", self.center.x, self.center.y);
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"topLeft: x = %f, y = %f", topLeft.x, topLeft.y);
NSLog(#"topRight: x = %f, y = %f", topRight.x, topRight.y);
NSLog(#"bottomLeft: x = %f, y = %f", bottomLeft.x, bottomLeft.y);
NSLog(#"bottomRight: x = %f, y = %f", bottomRight.x, bottomRight.y);
NSLog(#"self.center: x = %f, y = %f", self.center.x, self.center.y);
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:nil];
NSLog(#"touchesBegan: touchPoint: x = %f, y = %f", touchPoint.x, touchPoint.y);
if ([self isPoint:touchPoint inTriangle:topLeft :self.center :topRight]) {
NSLog(#"touchesBegan: UP");
direction = 1;
self.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"round_directions_button_pressed_up.png"]];
} else if ([self isPoint:touchPoint inTriangle:bottomLeft :self.center :bottomRight]) {
NSLog(#"touchesBegan: DOWN");
direction = 2;
self.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"round_directions_button_pressed_down.png"]];
} else if ([self isPoint:touchPoint inTriangle:topLeft :self.center :bottomLeft]) {
NSLog(#"touchesBegan: LEFT");
direction = 3;
self.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"round_directions_button_pressed_left.png"]];
} else if ([self isPoint:touchPoint inTriangle:topRight :self.center :bottomRight]) {
NSLog(#"touchesBegan: RIGHT");
direction = 4;
self.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"round_directions_button_pressed_right.png"]];
} else {
NSLog(#"touchesBegan: NOTHING");
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
self.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"round_directions_button_default.png"]];
}
- (BOOL) isPoint:(CGPoint)point inTriangle:(CGPoint)v1 :(CGPoint)v2 :(CGPoint)v3 {
BOOL b1, b2, b3;
b1 = ((point.x - v2.x) * (v1.y - v2.y) - (v1.x - v2.x) * (point.y - v2.y)) < 0.0f;
b2 = ((point.x - v3.x) * (v2.y - v3.y) - (v2.x - v3.x) * (point.y - v3.y)) < 0.0f;
b3 = ((point.x - v1.x) * (v3.y - v1.y) - (v3.x - v1.x) * (point.y - v1.y)) < 0.0f;
return ((b1 == b2) && (b2 == b3));
}
in view controller viewDidLoad:
CustomButton *customButton = [[CustomButton alloc] initWithFrame:CGRectMake(1, self.view.bounds.size.height - 106, 105, 105)];
[self.view addSubview:customButton];
Any help will be appreciated.
Thanks
If the size of the button doesn't change with rotation you can set points just once inside initWithFrame and use bounds instead of frame.
topLeft = CGPointMake(0, 0);
topRight = CGPointMake(self.bounds.size.width, 0);
bottomLeft = CGPointMake(0, self.bounds.size.height);
bottomRight = CGPointMake(self.bounds.size.width, self.bounds.size.height);
Then in touchesBegan use [touch locationInView:self]; to get the touch location in the button own coordinate system.
If the size changes, a solution can be to recalculate points on every touch so place the above code inside touchesBegan.
EDIT:
If you want to use local button coordinate you have to calculate the center because self.center contains center point of the view in the superview’s coordinate system.

Resources