8

I have a UIImageView and it has an image larger than the screen size. I have this UIImageView as a sub view of UIScrollView. Now, I am unable to scroll down. to view the whole image. But the zooming functionalities are working fine.

@IBOutlet weak var scrollView: UIScrollView!

var imageView = UIImageView();

override func viewDidLoad() {
    super.viewDidLoad()
}

func centerScrollViewContents(){
    let boundsSize = scrollView.bounds.size
    var contentsFrame = imageView.frame

    if contentsFrame.size.width < boundsSize.width {
       contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2
    }
    else { 
       contentsFrame.origin.x = 0
    }

    if contentsFrame.size.height < boundsSize.height {            
        contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2
    }
    else {
        contentsFrame.origin.y = 0
    }

    imageView.frame = contentsFrame
   // scrollView.frame = contentsFrame        
}

func scrollViewDidZoom(scrollView: UIScrollView) {
    centerScrollViewContents()
}

func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
    return imageView
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()

    // Dispose of any resources that can be recreated.
}

override func viewDidAppear(animated: Bool) {

    scrollView.delegate = self
    imageView.frame = CGRectMake(0, 0, scrollView.frame.size.width, scrollView.frame.size.height)

   // imageView.contentMode = UIViewContentMode.ScaleAspectFill
   // imageView.clipsToBounds = true
    imageView.image = UIImage(named: imgstr)

    var imagee = UIImage(named: imgstr)
    let size = imagee?.size
   // imageView.frame = CGRectMake(0, 0, size.width!, size.height!)
    imageView.contentMode = .Top
    scrollView.addSubview(imageView)

    scrollView.contentSize = size!
    let scrollViewFrame = scrollView.frame
    let scaleWidth = scrollViewFrame.size.width / scrollView.contentSize.width
    let scaleHeight = scrollViewFrame.size.height / scrollView.contentSize.height
    let minScale = min(scaleHeight, scaleWidth)

    scrollView.minimumZoomScale = 1
    scrollView.maximumZoomScale = 5
    scrollView.zoomScale = minScale

    centerScrollViewContents()   
}

enter image description here

2
  • All answers are wrong, you are using AutoLayout, so you can use frame property to change, you should create an IBOutlet for your ImageView top constraint and change it, plus see this google.co.in/… Commented May 3, 2015 at 11:49
  • You can use ImageScrollView open source, a zoomable and scrollable image view. github.com/huynguyencong/ImageScrollView Commented Mar 6, 2016 at 16:27

9 Answers 9

4
+25

You have to solve two main problems to your UIScrollView work

  1. One problem reside inside where you initialize all the data for the UIScrollView, I mean the function viewDidAppear.
  2. You must set the constraints for you UIScrollView like Top, Bottom, Left and Right to 0 respect the your SuperView.

If you put the code inside your viewDidAppear inside of your function viewDidLoad and delete your function viewDidAppear, it works fine as you want. Like in the following way:

override func viewDidLoad() {
    super.viewDidLoad()


    scrollView.delegate = self
    imageView.frame = CGRectMake(0, 0, scrollView.frame.size.width, scrollView.frame.size.height)

    // imageView.contentMode = UIViewContentMode.ScaleAspectFill
    // imageView.clipsToBounds = true
    imageView.image = UIImage(named: "imgstr.jpg")

    var imagee = UIImage(named: "imgstr.jpg")
    let size = imagee?.size
    // imageView.frame = CGRectMake(0, 0, size.width!, size.height!)
    imageView.contentMode = .Top
    scrollView.addSubview(imageView)

    scrollView.contentSize = size!
    let scrollViewFrame = scrollView.frame
    let scaleWidth = scrollViewFrame.size.width / scrollView.contentSize.width
    let scaleHeight = scrollViewFrame.size.height / scrollView.contentSize.height
    let minScale = min(scaleHeight, scaleWidth)

    scrollView.minimumZoomScale = 1
    scrollView.maximumZoomScale = 5
    scrollView.zoomScale = minScale

    centerScrollViewContents()
}

You must too set the constraints for the UIScrollView in your Storyboard

I though that the problem reside in the following difference:

  • viewDidAppear is called when the view is actually visible, and can be called multiple times during the lifecycle of a View Controller (for instance, when a Modal View Controller is dismissed and the view becomes visible again). This is where you want to perform any layout actions or do any drawing in the UI - for example, presenting a modal view controller. However, anything you do here should be repeatable. It's best not to retain things here, or else you'll get memory leaks if you don't release them when the view disappears.
  • viewDidLoad is called exactly once, when the view controller is first loaded into memory. This is where you want to instantiate any instance variables and build any views that live for the entire lifecycle of this view controller. However, the view is usually not yet visible at this point.

If you any problem I have a project ready to submit to Github if you want to see it.

UPDATE: After test it again your code, I resume your error to less code. Your code work fine, if you put your line imageView.frame = CGRectMake(0, 0, size!.width, size!.height) your code works fine without contraints.

Something like this :

override func viewDidAppear(animated: Bool) {


    scrollView.delegate = self        

    // imageView.contentMode = UIViewContentMode.ScaleAspectFill
    // imageView.clipsToBounds = true
    imageView.image = UIImage(named: "imgstr.jpg")

    var imagee = UIImage(named: "imgstr.jpg")
    let size = imagee?.size

    // This line should be here!!!
    imageView.frame = CGRectMake(0, 0, size!.width, size!.height)
    imageView.contentMode = .Top
    scrollView.addSubview(imageView)

    scrollView.contentSize = size!
    let scrollViewFrame = scrollView.frame
    let scaleWidth = scrollViewFrame.size.width / scrollView.contentSize.width
    let scaleHeight = scrollViewFrame.size.height / scrollView.contentSize.height
    let minScale = min(scaleHeight, scaleWidth)

    scrollView.minimumZoomScale = 1
    scrollView.maximumZoomScale = 5
    scrollView.zoomScale = minScale

    centerScrollViewContents()       

}

The key is that in your previous code you set the frame for the image as the frame of the scrollView not at the size of the image that is bigger than the scrollView.

I hope this help you.

Sign up to request clarification or add additional context in comments.

9 Comments

What do you mean by pinning it to super view in this case? Isn't the screen it's superview? I have updated my question to show how I am pinning it?
@AdamYoung Exactly that just unmark "Contraints to margin" and put the rest left, right, bottom and top to 0, is what I mean.
Let me know if you want to see my test project in Github
@AdamYoung See updated answer, I going to upload the project now
@AdamYoung This the link of the project test in Github github.com/Vkt0r/ScrollViewTest
|
3

Make sure you have enable userinteraction for scrollview: scrollview.userInteractionEnabled=YES

12 Comments

I am trying it but zooming is working fine. So it means it is already enabled.
@AdamYoung Still you have make sure by adding that line. I hope it will work for sure
Also make sure that size of your UIScrollView is less then the contentsize (ImageSize), then only it will scroll.
are you interested in using autolayout approach? you don't have to write code for autolayout . you can handle it with Interface builder only
Code snippet would be of great help
|
2
  • take a UIScrollView put a UIView (lets say it container view) inside the scrollview and then put imageview inside the containerView.

  • now apply the auto layout constraints to uiscrollview like this

left, right, top, bottom margins, width and height constraints in scrollview

  • now apply the autolayout constraints to the containerView

left, right, top, bottom margins, width and height constraints in containerView

  • now apply the autolayout constraints to the imageView

left, right, top, bottom constraints to the imageView

  • after this your autolayout structure must be like this

autolayout structure

  • after this write the following code in the ViewController.m

    - (void)viewWillAppear:(BOOL)animated
    {
       [super viewWillAppear:animated];
       [self.doubleTapGesture setNumberOfTapsRequired:2];
    }
    
    - (IBAction)handleDoubleTapGesture:(UITapGestureRecognizer *)sender 
    {    
       float newScale = self.scrollView.zoomScale *3;
     if (self.scrollView.zoomScale > self.scrollView.minimumZoomScale) 
      {
        [self.scrollView 
            setZoomScale:self.scrollView.minimumZoomScale animated:YES];
       }
       else       {      
        CGRect zoomRect = 
         [self zoomRectForScale:newScale
                       withCenter:
        [self.doubleTapGesture 
       locationInView:self.doubleTapGesture.view]];
           [self.scrollView zoomToRect:zoomRect animated:YES];
        }
      }
    
     - (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center 
     {    
        CGRect zoomRect;
    
        zoomRect.size.height = 
           self.contentViewHeightConstraint.constant / scale;
        zoomRect.size.width  = 
            self.contentViewWidthConstraint.constant  / scale;
    
        center = [self.contentView 
            convertPoint:center fromView:self.view];
    
        zoomRect.origin.x = center.x - ((zoomRect.size.width / 2.0));
        zoomRect.origin.y = center.y - ((zoomRect.size.height / 2.0));
    
         return zoomRect;
     }
    
    #pragma mark - UIScrollViewDelegate
    - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
    {
        return self.contentView;
    }
    
    - (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView 
                withView:(UIView *)view
    {
        self.ContentViewVerticalSpaceConstraint.constant = 0;
        [self.contentView layoutIfNeeded];
    }
    - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView 
                        withView:(UIView *)view atScale:(CGFloat)scale
    {
        if (scale <= 1)                    self.ContentViewVerticalSpaceConstraint.constant = 174;
            [self.contentView layoutIfNeeded];
        }
    }
    
  • now check it it will be working fine with the double tap and pinch gesture.

1 Comment

Thank you very much! The only thing I've needed to remove is ContentViewVerticalSpaceConstraint everything other works fine.
1

Try this:

imageView.frame = CGRectMake(0, 0, imageSize.height, imageSize.height)

Or

scrollView.contentSize = CGSizeMake(imageSize.width * 2, imageSize.height * 2)

In general, I add subviews in ViewDidLoad.

Comments

1

Make sure your UIScrollView's height not more than the view's height itself.

Sample code

@IBOutlet weak var scroller: UIScrollView!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    scroller.contentSize = CGSizeMake(400, 2300)
    scroller.showsHorizontalScrollIndicator = true
    scroller.scrollEnabled = true
}

Reference: http://blog.revivalx.com/2015/02/23/how-to-use-scroll-view-in-xcode-6-ios-8xcode6/

Comments

1

Enable UIImageView userinteraction.

imageView.userInteractionEnabled=true;

Comments

1

In order to Scroll vertically You have to set x axis as 0 in the content size of the scrollView. and set this in your viewDidLoad method.

Comments

1

You need to uncomment this line:

//imageView.frame = CGRectMake(0, 0, size.width!, size.height!)

of course, it will give you a compiler error. Since the optional value is size, the correct way is:

imageView.frame = CGRectMake(0, 0, size!.width, size!.height)

Comments

0

It isn't scrolling with drag gestures because of auto layout.
In viewDidLoad, auto layout will reset the content size after you define it. You have two options: you can disable auto layout, or you can set contentSize in viewDidLayoutSubviews.

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    scrollView.contentSize = CGSize(width:10, height:10)
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.