Zooming UIImage in a UIScrollView - objective-c

I currently have a custom class that implements UIScrollView.
I created one UIImageView and add it to a subview of the UIScrollView. It scrolls vertically and horizontally perfectly, but it seems to be ignoring the zooming stuff. Here is my code:
- (void) setUpBoard
{
// add board
UIImageView *imageHolder = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"grid.jpg"]];
[self addSubview:imageHolder];
self.contentSize = CGSizeMake(imageHolder.frame.size.width, imageHolder.frame.size.height);
self.indicatorStyle = UIScrollViewIndicatorStyleWhite;
self.maximumZoomScale = 5.0;
self.minimumZoomScale = 0.2;
self.zoomScale = 0.7;
self.clipsToBounds = YES;
}
How do I get it to zoom using standard pinch gestures? Any help is appreciated. Thanks!

From the UIScrollView Class Reference Overview:
The UIScrollView class can have a delegate that must adopt the UIScrollViewDelegate protocol. For zooming and panning to work, the delegate must implement both viewForZoomingInScrollView: and scrollViewDidEndZooming:withView:atScale:; in addition, the maximum (maximumZoomScale) and minimum (minimumZoomScale) zoom scale must be different.
I suspect that either you haven't assigned a delegate to the scroll view, or the delegate doesn't implement both of those methods.

Related

Animate NSButton resizing when modifying imagePosition property

I have an NSButton subclass in an autolayout environment. The subclass implements mouseEntered: and mouseExited: methods, which should change the positioning of the button's image. On mouseEntered: it is changed to NSImageLeft (showing the title) and on mouseExited: it is changed to NSImageOnly (not showing the title).
Autolayout takes care of the resizing of the NSButton subclass in my view hierarchy, but it does not look smooth as it is not using CoreAnimation for resizing the button width according to whether the title is to be shown or not. How can I let the resizing happen with an animation?
Open an animation group, enable implicit animations, change the button image position, and then force layout:
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context){
context.allowsImplicitAnimation = YES;
button.imagePosition = NSImageOnly;
[button.window layoutIfNeeded];
} completionHandler:nil];
I solved it by using the following methods:
- (void)mouseEntered:(NSEvent *)theEvent {
NSSize titleStringSize = [self.title sizeWithAttributes:#{NSFontAttributeName:[NSFont boldSystemFontOfSize:11.0]}];
self.widthConstraint.animator.constant = titleStringSize.width+self.originalWidth+5.0;
}
- (void)mouseExited:(NSEvent *)theEvent {
self.widthConstraint.animator.constant = self.originalWidth;
}
originalWidth and widthConstraint are properties of my NSButton subclass that are defined during awakeFromNib.

UIButton inside UIView doesn't respond to touch events

I've put a UIButton inside a custom UIView and the button is not receiving any touch events (it doesn't get into the highlighted state, so my problem is not about being unable to wire up a touch inside up handler). I've tried both putting it into the XIB in Interface Builder, and also tried programatically adding the UIButton into the UIView seperately, both ended with no luck. All my views are inside a UIScrollView, so I first though UIScrollView may be blocking them, so I've also added a button programatically exactly the same way I add my custom view into UIScrollView, and the button worked, elimination the possibility of UIScrollView could be the cause. My View's hiearchy is like this:
The button is over the image view, and the front layer isn't occupying my button completely, so there's no reason for me not be physically interacting with the button. At my custom view's code side, I'm creating my view as such:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
UIView *sub = [[[NSBundle mainBundle] loadNibNamed:#"ProfileView" owner:self options:nil] objectAtIndex:0];
[self addSubview:sub];
[sub setUserInteractionEnabled:YES];
[self setUserInteractionEnabled:YES];
CALayer *layer = sub.layer;
layer.masksToBounds = YES;
layer.borderWidth = 5.0;
layer.borderColor = [UIColor whiteColor].CGColor;
layer.cornerRadius = 30.0;
/*layer.shadowOffset = CGSizeZero;
layer.shadowRadius = 20.0;
layer.shadowColor = [[UIColor blackColor] CGColor];
layer.shadowOpacity = 0.8;
*/
}
return self;
}
I've tried all combinations of setUserInteractionsEnabled, and had no luck. (Yes, also set them to checked in Interface Builder too). I've also read in another question with a similar problem that I should try overriding 'canBecomeFirstResponder' to return 'YES' and I've also done that too. But the problem persists, I can't click the button. I've not given any special properties, settings to the button, it's just a regular one. My other objects in the view (labels below, image view behind the button etc.) are working properly without problems. What could be possibly wrong here?
Thanks,
Can.
UPDATE: Here is a quick reproduction of the problem: https://dl.dropbox.com/u/79632924/Test.zip
Try to run and click the button.
Looking at the test project, I believe your problem in the way you create TestView, you do not specify the frame for it, so basically the parent view is 0 size, and the subviews you see from XIB extending out of the parent view and thus do not get anything in responder chain.
You should either specify the frame when creating TestView, or adjust the frame after loading XIB file.
I have had this problem as well. The cause for me was that the UIButton superview frame was of height 0, so I believe that even though a touch was happening, it was not being passed down to the button.
After making sure that the button's superview took a larger rectangle as a frame the button actions worked.
The root cause for this problem on my side was a faulty auto layout implementation (I forgot to set the height constraint for the button's superview).
I've found the solution. I was initializing my custom view as:
MyView *view = [[MyView alloc] init];
I've initialized it instead with a frame of my view's size, and it started responding to events:
CGRect rect = CGRectMake(0,0,width,height);
MyView *view = [[MyView alloc] initWithFrame:rect];
Storyboard Solution
Just for anyone wanting a solution to this when using storyboards and constraints.
Add a constraint between the superview (containing the button) and the UIButton with an equal heights constraint.
In my case, I had selected embed UIButton in a UIView with no inset on the storyboard. Adding the additional height constraint between the UIButton and the superview allowed the UIButton to respond to touches.
You can confirm the issue by starting the View Debugger and visually confirm that the superview of the UIButton is not selectable.
(Xcode 11, *- Should also work in earlier versions)

UILabel scaling with UIScrollView

I have a UIScrollView that displays and Image and it scrolls fine and everything. What I want to do is add a UILabel to the UIScrollView to display the title of the image. I managed to do that, but when I zoom out the UILabel does not zoom with the scroll View and stays in the same place on the screen. How would I make it so the label scales with the scrollView Image? Here is the code I have:
[super viewDidLoad];
// Do any additional setup after loading the view.
self.scrollView.delegate = self;
//This just creates a image from a URL
NSURL * photoURL = [FlickrFetcher urlForPhoto:self.photoCellName format:2];
NSData * photoData = [NSData dataWithContentsOfURL:photoURL];
self.imageView.image = [UIImage imageWithData:photoData];
//Setting up scroll View
self.scrollView.contentSize= self.imageView.image.size;
self.imageView.frame = CGRectMake(0, 0, self.imageView.image.size.width, self.imageView.image.size.height);
NSLog(#"Name = %#", [self.photoCellName valueForKeyPath:#"description._content"]);
//Assigning title to the label
self.textLabel.text = [self.photoCellName objectForKey:#"title"];
Make sure label is the subview of your scrollview.
I'm guessing you are providing the UIImageView as the View that will be zoomed by the UIScrollView by implementing the method in the UIScrollViewDelegate.
If not, I'm not sure how your zooming is working then. If you are providing it, you'll have to return a UIView that contains as subviews your UILabel and your UIImageView and you will have to manually apply transformations to the UIView to resize it.
I guess that a similar question was answered in this SO thread, and Dimme (the one that answered it)provided a complete solution with source code, hope it helps!
You should check if you setup autoresizingMask property of your UILabel
self.label.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
You can do it in IB too. Then if you will change the frame of its superview the frame of your label will be updated during - (void)setNeedsLayout handling process
... and DO NOT block the main thread creating images from url in - (void)viewDidLoad!

how to perform double tap on imageView

I have work on touch event but that would be not work because of I take imageView in ScrollView so,that when I touch the image that directly work scrollview but not work touch on image so give any suggestion and source code which is apply in my code.....
As frauen1 says in their answer here:
1) In the UIScrollView class, set the value of canCancelContentTouches
to NO - this tells the UIScrollView class to allow touches within
subviews (or, in this case, in subviews of subviews).
2) In my "card" class, set exclusiveTouch to YES - this tells the
subview it owns the touches inside of it.
Now it will allow double tap on ImageView with following code
UITapGestureRecognizer *tapRecognizer;
self.imgViewGVC.userInteractionEnabled = YES;
tapRecognizer = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(handleTapView:)];
tapRecognizer.numberOfTapsRequired = 2;
[self.ImageView addGestureRecognizer:tapRecognizer];
[tapRecognizer release];

drawRect cropping in UIScrollView

I am trying to draw an image into a UIView subclass overriding drawRect. This image drawing class needs moving and zooming capabilities, so I made it a subview of a scrollview.
My problem is that my image seems to get cropped, either by the screen or the scrollView bounds (the image is larger than the screen). I don't have a clue why, this seems to e pretty basic stuff.
The view hierarchy in my ViewController looks like this:
View Controller
View
ScrollView
MapView
I've created outlets for the scroll view and the map view (which is the view implementing drawRect).
My ViewController initial setup code for configuring the scroll view looks like this:
- (void)viewDidLoad
{
[super viewDidLoad];
scrollView.delegate = self;
scrollView.contentSize = CGSizeMake(450, 476);
scrollView.minimumZoomScale = 0.6;
scrollView.maximumZoomScale = 6.0;
}
My drawRect implementation:
- (void)drawRect:(CGRect)rect
{
UIImage *myImage = [UIImage imageNamed:#"map.jpg"];
CGRect rectangle = CGRectMake(0,0,450,476);
[myImage drawInRect:rectangle];
}
The image is draggable and zoomable within the scroll view, but it's cropped at what seems to be the screen bounds.
Any help would be appreciated.
drawRect can't draw outside the rect passed as a parameter to the drawRect method, which is determined by the view frame. Make your view 1200,1200 and make sure that clipToBounds is disabled on all the containing views.
Your problem is probably in drawInRect. From documentation of UIImage class:
drawInRect:
Draws the entire image in the specified rectangle, scaling it as needed to fit.
Make that rectangle bigger as you wish and center it in UIImageView. This question is answered here UIScrollView image/photo viewer with paging enabled and zooming