Pinch-In Zoom Not working as expected - ios

I have searched a lot but not able to find anything fruitful.Here is my scenario:
I am making a horizontal Image Slider(UIScrollView) which consist of multiple images.
The slider is working fine.
But the problem arises when I implement Pinch-In Zoom-In-Out`.
I am using this delegate method to zoom a particular Image:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return imgView;
}
Whenever I zoom-In any image the Image next to it changes its position and the image which I am zooming after I leave my finger the image slighly shift to left and top . It not stoping where I want to stop.
What I have Done: Programatically created image and added them to scrollView.
xPointer = 0;
for(i=0;i<[imgArr count];i++)
{
UIImageView *imgToZoom= [[UIImageView alloc]init];
imgToZoom.image = [imgArr objectAtIndex:i];
imgToZoom.tag = i+100;
imgToZoom.frame = CGRectMake(xPointer, _imagesScrollView.frame.origin.y-10, self.view.frame.size.width,_imagesScrollView.frame.size.height/2);
[imgToZoom setUserInteractionEnabled:YES];
[imgToZoom setMultipleTouchEnabled:YES];
[_imagesScrollView addSubview:imgToZoom];
xPointer = xPointer+self.view.frame.size.width;
}
_imagesScrollView.contentSize = CGSizeMake(xPointer, _imagesScrollView.frame.size.height);
How can I implement Pinch In zoom. As When I done it using apple Doc My other images are changing there position.And Zoom in also not to the point.

Related

UIPageViewController with UISlider inside controller - increase hit area of slider

I have multiple controllers in my PageViewController and in one controller I have a few sliders. Now there is a problem that user must touch exactly slider circle (I am not sure about right expression, thumb? - that moving part) and I would like to increase area in which reacts slider and not the whole PageViewController. I tried these solutions but it doesn't help:
thumbRectForBounds:
- (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value
{
return CGRectInset ([super thumbRectForBounds:bounds trackRect:rect value:value], 15, 15);
}
Increase hitTest area:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if (CGRectContainsPoint(CGRectInset(self.frame, 200, 200), point) || CGRectContainsPoint(CGRectInset(self.frame, 200, 200), point)) {
return self;
}
return [super hitTest:point withEvent:event];
}
I have these methods in my custom slider class because I would like to reuse this. Last thing what I found and not tried yet is create some object layer over slider which "takes" gesture and disable PageViewController but I am not sure how to do it and I am not sure if it's good/best solution.
I am not a big fan of the UISlider component because as you noticed, it is not trivial to increase the hit area of the actual slider. I would urge you to replicate the UISlider instead using a pan gesture for a much better user experience:
i. create a slider background with a seperate UIImageView with a slider image.
ii. create the PanGesture:
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:);
[imageView addGestureRecognizer:pan];
iii. implement handlePan Method:
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {
//pan (slide) begins
CGPoint translation = [recognizer locationInView:self.view];
translation.y = self.slideImage.center.y;
self.slideImage.center = translation;
if(recognizer.state == UIGestureRecognizerStateEnded) {
LTDebugLog(#"\n\n PAN, with spot: %f\n\n", self.slideImage.center.x);
//do something after user is done sliding
}
}
The big benefit of this method is that you will have a much better user experience as you can make the responsive UIImageView as big as you want.
Alternatively, you could subclass a UISlider and increase the hit space there, although in my experience this gives mixed results.
Hope this helps
In your CustomSlider class override thumbRectForBounds method:
Simply return rect value as you required:
- (CGRect)thumbRectForBounds:(CGRect)bounds trackRect:(CGRect)rect value:(float)value
{
return CGRectMake (bounds.origin.x, bounds.origin.y, yourWidthValue, yourHeightValue );
}
Change yourWidthValue and yourHeightValue as per your requirement. And then while using
Create object like below:
CustomSlider *slider = [[CustomSlider alloc] initWithFrame:CGRectMake(0, 0, 300, 20)];
[slider thumbRectForBounds: slider.bounds trackRect:slider.frame value:15.f]; // change values as per your requirements.
Hope this helps.
Create a custom thumb image which has a large empty margin and set that on your slider, like this:
[theSlider setThumbImage:[UIImage imageNamed:#"slider_thumb_with_margins"] forState:UIControlStateNormal];
To make the image, get a copy of the system thumb image using any one of a number of UIKit artwork extractors (just search the web for one). Open the thumb image in Photoshop and increase the canvas size by twice the margin you want to add. Make sure you change the canvas size and not the image size, as the image size will stretch the image to fill the new size. This will put empty space around the thumb which will be part of the hit-test area but since it is all transparent it won't change the look of the slider.

iOS: detecting touch on image within UIImageView containing multiple images

I got an UIImageView composed of two images with transparancy channel activated.
The view looks something like this:
image
I would like to be able to detect precisely the touches within the center circle and distinguish them from the ones in the outern circle.
I am thinking of a collision detection algorithm based the difference between two circles. First test in the outern layer to see if there is a collision at all and then in the inner layer. If in the inner layer then activate inner botton otherwise active outern button.
Any help or suggestion in this?
Shall I create a github repo so everyone could contribute in it?
Here something than can help you:
UIImageView *myImageView;
// In viewDidLoad, the place you are created your UIImageView place this:
myImageView.userInteractionEnabled = YES;
UITapGestureRecognizer *tapInView = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapInImageView:)];
[myImageView addGestureRecognizer:tapInView];
}
-(void)tapInImageView:(UITapGestureRecognizer *)tap
{
CGPoint tapPoint = [tap locationInView:tap.view];
CGPoint centerView = tap.view.center;
double distanceToCenter = sqrt((tapPoint.x - centerView.x)*(tapPoint.x - centerView.x) + (tapPoint.y - centerView.y)*(tapPoint.y - centerView.y) );
if (distanceToCenter < RADIUS) {
// It's in center
} else {
// Touch outside
}

Tap gesture on stacked images

i want to show up images in my view and add the tap gesture to do some stuff.
My code looks like this for the image creation
for(int i = 0; i < 5; i++) {
UIImageView *imageToMove =
[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"icon1.png"]];
imageToMove.frame = CGRectMake(((float)rand() / RAND_MAX) * 1024, ((float)rand() / RAND_MAX) * 768 , 95, 95);
[imageToMove setUserInteractionEnabled:YES];
[imageToMove addGestureRecognizer:singleTap];
[self.view addSubview:imageToMove];
}
and this simple function to get some feedback when a image is tapped
- (void)tapDetected {
NSLog(#"single Tap on imageview");
}
My Problem is, only one (IMHO the last one added) image is touchable. The other images "behind" can't be accessed.
Is there a possibility to solve this?
It is not entirely clear what you would like to do when tapping on stacked images (I mean, the natural thing would be that the image you touch can move, and this is should be accomplished by your code); in any case, try with:
singleTap.cancelsTouchesInView = NO;
This will make your gesture recognizers not cancel the tap they handle, so the holding view will also receive the events. If this does not help, have a look at the UIGestureRecognizerDelegate protocol and specifically at the method
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer
which should allow to fine-control how your gesture recognizers co-exist.

UIScrollView zoom in bounce

I have embedded an image view into a scroll view for zooming purposes. Everything works great but if the user choses to zoom in then pan in any direction the user can slightly pull the ScrollView off the screen bounds exposing the content i have behind the scrollview before bouncing back. I want to disable this bouncing when zoomed in but don't know how. This only happens when zoomed in. At normal zoom scale you can't do it. Heres my code I have gone through the UIScrollView Class Reference and have commented out my attempts at disabling it but it doesn't work!
zoomScrollView.contentSize = CGSizeMake(enlargedPhotoImageView.frame.size.width , enlargedPhotoImageView.frame.size.height);
zoomScrollView.maximumZoomScale = 10;
zoomScrollView.minimumZoomScale = 1;
zoomScrollView.clipsToBounds = YES;
zoomScrollView.delegate = self;
zoomScrollView.zoomScale = 1;
//zoomScrollView.alwaysBounceHorizontal = NO;
//zoomScrollView.alwaysBounceVertical = NO;
//zoomScrollView.bouncesZoom = NO;
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
if(scrollView == zoomScrollView){
return enlargedPhotoImageView;
}else{
return nil;
}
}
zoomScrollView.bounces = NO;
Will prevent overscroll. But...scrollviews that don't bounce usually feel very weird to users; bear in mind that there's probably a better way to accomplish whatever you're trying to do.

iOS: UIScrollView zooming programmatically not working

I have a pageable UIScrollView which contains different kind of informations like UITables but also zoomable images. Therefore I set up a pageable main-ScrollView and as subviews I added zoomable image-ScrollViews with the images as content.
Works everything fine, just I fail to set the smaller current zoom scale of the imageScrollViews.
UIImageView *imageView = [[UIImageView alloc] initWithImage:Image];
//storing a link to the imageView
[imagelinkArray addObject:imageView];
CGRect ScrollViewImageRect;
ScrollViewImageRect = CGRectMake((self.scrollView.frame.size.width) * i, 0, 320, self.scrollView.frame.size.height);
float widthfactor = ScrollViewImageRect.size.width / imageView.frame.size.width;
float heightfactor = ScrollViewImageRect.size.height / imageView.frame.size.height;
float zoomscale = MIN(widthfactor, heightfactor);
UIScrollView *imageScrollView = [[UIScrollView alloc] initWithFrame:ScrollViewImageRect];
imageScrollView.contentSize = CGSizeMake(imageView.frame.size.width, imageView.frame.size.height);
imageScrollView.delegate = self;
[imageScrollView setMinimumZoomScale:zoomscale];
[imageScrollView setMaximumZoomScale:1.5];
[imageScrollView addSubview:imageView];
//doesn't work:
[imageScrollView setZoomScale:0.5 animated:YES];
[self.scrollView addSubview:imageScrollView];
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return [imagelinkArray objectAtIndex:page];
}
The main-ScrollView and the image-ScrollViews are drawn perfectly and it's possible to zoom and page properly. The minimum zoom factor is calculated also correct. When I zoom out I can zoom until the image limits are reached. However the first time I page to the image-ScrollView it's current zoom scale is always 1.0 while it should be the minimum scale.
Wherever I set the zoom scale in the code above it doesn't work:
[changeScrollView setZoomScale:changeScrollView.minimumZoomScale animated:YES];
If I log the current zoom scale i always get 1.0;
The only thing which works is changing the zoom scale in the - (void)scrollViewDidScroll: method, which of course doesn't help a lot since zooming also calls it which resets the zoom immediately. But at least I could figure out, that the code somehow works. I have the feeling a UIScrollView doesn't zoom when it's not visible on the screen right now. How can I fix this?
Update:
Okay. In the meantime I figured out that the problem most likely comes from my base layout of "sub-viewing" ScrollViews into another ScrollView. When I zoom one of the images and log the current zoom factor of the ScrollViews they are all the same (main ScrollView as well as ALL sub-ScrollViews).
What could be the reason for it or how could I solve it with a different layout?
I think viewForZoomingInScrollView: may not be getting called by the scrollview. Try to add a breakpoint and check what you're returning there.
Your code doesn't work because you havent set minimumZoomScale ,which has default value of 1.0 . Since you are trying to set 0.5 which is below the default value, it wouldn't work.
Add following line just after the line which sets maximumZoomScale.
[imageScrollView setMinimumZoomScale:0.25];
As user Rivera pointed out the return value of viewForZoomingInScrollView: was off course not right.
I always returned the current visible page shown in the scrollView. Which means setting the zoom in viewDidAppear doesn't change anything.
Here is the correct code: I made a function which will always resets both images left and right of the current visible scroll page:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
[self updateImageSize];
}
- (void)updateImageSize
{
updatePage = updatePage + 1;
if (updatePage < imagescrolllinkArray.count) {
UIScrollView *changeScrollView = (UIScrollView*)[imagescrolllinkArray objectAtIndex:updatePage];
[changeScrollView setZoomScale:changeScrollView.minimumZoomScale];
}
updatePage = updatePage - 2;
if (updatePage > -1) {
UIScrollView *changeScrollView = (UIScrollView*)[imagescrolllinkArray objectAtIndex:updatePage];
[changeScrollView setZoomScale:changeScrollView.minimumZoomScale];
}
//reset to current view
updatePage = updatePage + 1;
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return [imagelinkArray objectAtIndex:updatePage];
}
and in viewDidAppear I added the following to update the first image before any dragging.
if (i == 1) {
updatePage = 0;
[imageScrollView setZoomScale:imageScrollView.minimumZoomScale];
}
In the meantime I figured out that the code below can under certain circumstances make problems. Sometimes when I zoom in and out from an image the main ScrollView can't be scrolled anymore, so there is no way to get to the next image, except of triggering the pageControl or except of zooming into the image and then scrolling to its borders so the main ScrollView jumps to the next page.
Means the problem only occurs when the image is fully zoomed out (.scale = .minimumscale). I don't understand exactly when and why it happens. Logging viewDidScroll returns nothing in this situations.
Anybody experienced similar problems?

Resources