How would I implement pinch to close functionality in UIScrollView? - ios

When the user zooms far enough out of the image by pinching out, then releases, I want it to close the UIImageView/scroll view, basically exiting the picture viewer.
How would I go about doing this? scrollViewDidEndZooming is called after it animates back into place, so I can't use that, and none of the other delegate methods seem helpful.

i have create this effect for one of my app, dont forget to set delegate of your scrollview.
you need to update the private method with your pinch gesture(thats all)
code for .h file
#import <UIKit/UIKit.h>
#interface ImageViewerController : UIViewController<UIScrollViewDelegate>
// The scroll view used for zooming.
#property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
// The image view that displays the image.
#property (weak, nonatomic) IBOutlet UIImageView *imageView;
// The image that will be shown.
#property (strong, nonatomic) NSString *imageUrlString;
#end
code for .m
#import "ImageViewerController.h"
#interface HNImageViewerController ()
- (IBAction)handleSingleTap:(UIButton*)tapGestureRecognizer;
#end
#implementation ImageViewerController
- (void)viewDidLoad {
[super viewDidLoad];
[self.imageView setImage:[UIImage imageNamed:#"placeholder-image"]];
self.scrollView.delegate=self;
}
- (BOOL)prefersStatusBarHidden {
return YES;
}
#pragma mark - UIScrollViewDelegate methods
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return self.imageView;
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
if (self.scrollView.zoomScale == self.scrollView.minimumZoomScale) {
[self dismissViewControllerAnimated:YES completion:nil];
}
}
#pragma mark - Private methods
- (IBAction)handleSingleTap:(UIButton *)tapGestureRecognizer {
[self dismissViewControllerAnimated:YES completion:nil];
}

Related

How to get viewForZoomingInScrollView to work across multiple UIViewControllers in Xcode?

I'm relatively new to Xcode, and am in the process of making an app in Objective C with several viewControllers each with a single UIScrollView containing a single UIImage that can be zoomed and scrolled.
This code works for the first image (dermatomes), but I can't figure out how to tweak the UIView to enable zooming and scrolling on the second image (anatomicPlanes). Currently the second image imports correctly to the second UIScrollView, but when I try to zoom it just jumps down and right and remains static there.
The size of the UIScrollViews were set using Interface Builder, no problems there.
viewController.h:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UIScrollViewDelegate> {
IBOutlet UIScrollView *dermatomeScrollView;
UIImageView *dermatomesImageView;
IBOutlet UIScrollView *anatomicPlaneScrollView;
UIImageView *anatomicPlanesImageView;
}
#property (strong, nonatomic) IBOutlet UIScrollView *dermatomeScrollView;
#property (strong, nonatomic) IBOutlet UIImageView *dermatomesImageView;
#property (strong, nonatomic) IBOutlet UIImageView *anatomicPlanesImageView;
#property (strong, nonatomic) IBOutlet UIScrollView *anatomicPlaneScrollView;
#end
viewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize dermatomeScrollView, anatomicPlanesImageView, dermatomesImageView, anatomicPlaneScrollView;
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return dermatomesImageView;
}
- (void)viewDidLoad {
[super viewDidLoad];
UIImageView *dermatomes = [[UIImageView alloc]
initWithImage:[UIImage imageNamed:#"dermatomes.jpg"]];
self.dermatomesImageView = dermatomes;
dermatomeScrollView. maximumZoomScale = 1.2;
dermatomeScrollView. minimumZoomScale = 0.4;
dermatomeScrollView. delegate = self;
[dermatomeScrollView addSubview:dermatomesImageView];
dermatomeScrollView.zoomScale = 0.6;
UIImageView *planes = [[UIImageView alloc]
initWithImage:[UIImage imageNamed:#"anatomic planes.jpg"]];
self.anatomicPlanesImageView = planes;
anatomicPlaneScrollView. maximumZoomScale = 1.2;
anatomicPlaneScrollView. minimumZoomScale = 0.4;
anatomicPlaneScrollView. delegate = self;
[anatomicPlaneScrollView addSubview:anatomicPlanesImageView];
anatomicPlaneScrollView.zoomScale = 0.6;
}
Any help is appreciated!
You need to return the correct view based on the scroll view that is requesting. Every method in the delegate pattern is passed a reference to the originator of the method call, so your delegate implementation can handle it differently. In this case, the originator of the delegate method call is the scroll view:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
if (scrollView == dermatomeScrollView) {
return dermatomesImageView;
}
return anatomicPlanesImageView;
}
If you add more scrollviews, you'll have to extend this method further.

Keep same view(s) in multiple controllers

I'm currently developing an app that has three buttons at the bottom of the layout (for customization reasons I couldn't use TabBar Controller or Segmented Control).
When I click one of these buttons, a new view should show up and inherite the buttons bar, along with its state (buttons can be in selected or unselected state).
I'm completely new to iOS development, so I tried following this guide (http://www.thinkandbuild.it/working-with-custom-container-view-controllers/), but problem is when I click a button, child view doesn't show up.
ContainerViewController.h
#interface ContainerViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIButton *firstButton;
#property (weak, nonatomic) IBOutlet UIButton *secondButton;
#property (weak, nonatomic) IBOutlet UIButton *thirdButton;
#property (weak, nonatomic) IBOutlet UIView *detailView;
- (IBAction)click:(id)sender;
#end
ContainerViewController.m
#import "ContainerViewController.h"
#import "FirstViewController.h"
#interface ContainerViewController ()
#property UIContainerViewController *currentDetailContainerViewController;
#end
#implementation ContainerViewController
#synthesize firstButton, secondButton, thirdButton;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)click:(id)sender
{
// switch buttons state
// ...
[self addDetailController:sender];
}
- (void)presentDetailController:(UIContainerViewController*)detailVC{
//0. Remove the current Detail View Controller showed
if(self.currentDetailContainerViewController){
[self removeCurrentDetailContainerViewController];
}
//1. Add the detail controller as child of the container
[self addChildContainerViewController:detailVC];
//2. Define the detail controller's view size
detailVC.view.frame = [self frameForDetailController];
//3. Add the Detail controller's view to the Container's detail view and save a reference to the detail View Controller
[self.detailView addSubview:detailVC.view];
self.currentDetailContainerViewController = detailVC;
//4. Complete the add flow calling the function didMoveToParentContainerViewController
[detailVC didMoveToParentContainerViewController:self];
}
- (void)removeCurrentDetailContainerViewController{
//1. Call the willMoveToParentContainerViewController with nil
// This is the last method where your detailContainerViewController can perform some operations before neing removed
[self.currentDetailContainerViewController willMoveToParentContainerViewController:nil];
//2. Remove the DetailContainerViewController's view from the Container
[self.currentDetailContainerViewController.view removeFromSuperview];
//3. Update the hierarchy"
// Automatically the method didMoveToParentContainerViewController: will be called on the detailContainerViewController)
[self.currentDetailContainerViewController removeFromParentContainerViewController];
}
- (CGRect)frameForDetailController{
CGRect detailFrame = self.detailView.bounds;
return detailFrame;
}
- (void)addDetailController:(id)sender {
FirstViewController *detailVC = [[FirstViewController alloc]initWithString:#"First view"];
[self presentDetailController:detailVC];
}
#end
FirstViewController.h
#import <UIKit/UIKit.h>
#class ContainerViewController;
#interface FirstViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *label;
- (id)initWithString:(NSString*)string;
#end
FirstViewController.m
#import "FirstViewController.h"
#interface FirstViewController (){
NSString *text;
}
#end
#implementation FirstViewController
- (id)initWithString:(NSString*)string {
self = [super init];
if(self){
text = string;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.label.text = text;
}
#end

iOS show UIImage full screen with zooming (pinch and double tap) enabled

I have an UIImage captured from the camera with UIImagePickerController.
Now after the user clicks on it, I'd like it to show full screen and be able to to zoom it in and out using pinch gestures and also the double tap gesture to zoom in a particular area. In other words, I'd like to emulate what the ios's default image browser does.
I display the captured image in an UIImageView with:
self.imageView.contentMode = UIViewContentModeScaleAspectFill;
which makes the image go full screen. But how do I implement zooming. Do I need to do it from scratch using gesture recognizers? Or maybe there's a default image display view with all that implemented I am not aware of?
i have create this effect for one of my app, dont forget to set delegate of your scrollview.
code for .h file
#import <UIKit/UIKit.h>
#interface ImageViewerController : UIViewController<UIScrollViewDelegate>
// The scroll view used for zooming.
#property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
// The image view that displays the image.
#property (weak, nonatomic) IBOutlet UIImageView *imageView;
// The image that will be shown.
#property (strong, nonatomic) NSString *imageUrlString;
#end
code for .m
#import "ImageViewerController.h"
#interface HNImageViewerController ()
- (IBAction)handleSingleTap:(UIButton*)tapGestureRecognizer;
#end
#implementation ImageViewerController
- (void)viewDidLoad {
[super viewDidLoad];
[self.imageView setImage:[UIImage imageNamed:#"placeholder-image"]];
self.scrollView.delegate=self;
}
- (BOOL)prefersStatusBarHidden {
return YES;
}
#pragma mark - UIScrollViewDelegate methods
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return self.imageView;
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
if (self.scrollView.zoomScale == self.scrollView.minimumZoomScale) {
[self dismissViewControllerAnimated:YES completion:nil];
}
}
#pragma mark - Private methods
- (IBAction)handleSingleTap:(UIButton *)tapGestureRecognizer {
[self dismissViewControllerAnimated:YES completion:nil];
}
This is very easy to implement:
- (IBAction)handlePinch:(UIPinchGestureRecognizer *)recognizer;
and then:
- (IBAction)handlePinch:(UIPinchGestureRecognizer *)recognizer {
recognizer.view.transform = CGAffineTransformScale(recognizer.view.transform, recognizer.scale, recognizer.scale);
recognizer.scale = 1;
}

UIButton not run action after device rotate

i have my button, created from storyboard:
#property (weak, nonatomic) IBOutlet UIButton *plusOneBtnPoisonTwo;
with its method:
- (IBAction)plusOnePlayerTwoPoison:(id)sender;
then I check device rotation and set new position:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
// NSLog(#"%d", toInterfaceOrientation);
if(!UIInterfaceOrientationIsPortrait(toInterfaceOrientation)){
self.plusOneBtnPoisonTwo.center = CGPointMake(284, 406);
}
}
the button moves in the new position, but the method plusOnePlayerTwoPoison is no more triggered...
Any Idea?
Thanks.
Try using this instead. Its just a guess that it may resolve your problem.
#property (retain, nonatomic) IBOutlet UIButton *plusOneBtnPoisonTwo; //change to retain
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
//add button action manually by code
[plusOneBtnPoisonTwo addTarget:self action:#selector(plusOnePlayerTwoPoison:) forControlEvents:UIControlEventTouchDown];
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
// NSLog(#"%d", toInterfaceOrientation);
if(!UIInterfaceOrientationIsPortrait(toInterfaceOrientation)){
[plusOneBtnPoisonTwo setFrame:CGRectMake(284, 406,50,100)];
}
}

Having delegate problems for my Navigation controller

so i have a navigation controller, and in it i have a view and a scrollview embedded in that view. My goal is to make my program scroll to a location when it is close to it.
to do this i added to outlets to my vc. one is the scroll view and the other is the view. The view is just a big rectangle about twice as wide as the iphones screen and slightly higher. My scroll view scrolls only horizantally, and whenever i lift my finger from scrolling, my goal is if the iphones bounds are within the views bounds. I want the scroll view to manually scroll to the middle of that view. (if you can think of a game menu in angry birds or cut the rope, when the user is scrolling between level packs horizantally, when the user lets go from scrolling it sort of zaps into place to the level the user let go by, this is what i want to mimick).
so, heres my code for both my view and my vc. The only thing i did with storyboards is that i hooked up the two outlets, and set the size of my view.
(the level packs is the vc and the other one is the view).
#import <UIKit/UIKit.h>
#import "HorizantalLockingView.h"
#interface LevelPacks : UIViewController <ViewDelegate>
#property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
#property (weak, nonatomic) IBOutlet HorizantalLockingView *lockingView;
#end
#import "LevelPacks.h"
#implementation LevelPacks
#synthesize scrollView=_scrollView;
#synthesize lockingView = _lockingView;
-(void)viewDidAppear:(BOOL)animated
{
CGSize size;
size.width=825;
size.height=460;
self.scrollView.contentSize=size;
self.scrollView.contentOffset=CGPointMake(0, 0);
}
-(void)viewDidLoad
{
[super viewDidLoad];
self.lockingView.delegate=self;
}
- (void)viewDidUnload
{
[self setLockingView:nil];
[super viewDidUnload];
self.scrollView=nil;
// Release any retained subviews of the main view.
}
#end
#import <UIKit/UIKit.h>
#protocol ViewDelegate
#property (nonatomic, weak) UIScrollView *scrollView;
#end
#interface HorizantalLockingView : UIView
#property (nonatomic, weak) IBOutlet id <ViewDelegate> delegate;
#end
#import "HorizantalLockingView.h"
#implementation HorizantalLockingView
#synthesize delegate=_delegate;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
CGRect location=self.superview.bounds;
NSLog(#"dkfjdkjf");
if (CGRectContainsRect(self.frame, location))
{
[self.delegate.scrollView scrollRectToVisible:CGRectMake(284, 190, 157, 119) animated:YES];
}
}
#end
o, and i did the nslog earlier to see if the method would even do anything, and the nslog never even ran, so obviously somethings wrong.
Im kind of new to this, any help would really be great!
Enabling paging will automatically do this for you.
scrollView.pagingEnabled=YES;
Also adding a UIPageControl and using the UIScrollView delegate methods to update the page control will add a good usability

Resources