IOS: add imageview in a scrollview to have zoom

后端 未结 4 1772
走了就别回头了
走了就别回头了 2020-12-02 09:39

I want to set a UIImageView with a UIImage and put this imageview inside a UIScrollView to obtain a zoom of this image; and I want this UIIma

相关标签:
4条回答
  • 2020-12-02 10:00
    1. Set your view controller up as a <UIScrollViewDelegate>
    2. Draw your UIScrollView the size you want for the rectangle at the center of the view. Set the max zoom in the inspector to something bigger than 1. Like 4 or 10.
    3. Right click on the scroll view and connect the delegate to your view controller.
    4. Draw your UIImageView in the UIScrollView and set it up with whatever image you want. Make it the same size as the UIScrollView.
    5. Ctrl + drag form you UIImageView to the .h of your View controller to create an IBOutlet for the UIImageView, call it something clever like imageView.
    6. Add this code:

      -(UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView
      {
          return self.imageView;
      }
      
    7. Run the app and pinch and pan til your heart's content.

    0 讨论(0)
  • 2020-12-02 10:02

    I have written an example application which also supports AutoLayout and Storyboards to demonstrate this behavior. I hope it saves everyone time trying to figure this out: http://rexstjohn.com/facebook-like-ios-photo-modal-gallery-swipe-gestures/.

    0 讨论(0)
  • 2020-12-02 10:11

    With Swift 4 and iOS 11, you can use one of the two following solutions in order to solve your problem.


    #1. Using insets

    ViewController.swift

    import UIKit
    
    final class ViewController: UIViewController {
    
        private let scrollView = ImageScrollView(image: UIImage(named: "image")!)
    
        override func viewDidLoad() {
            view.backgroundColor = .black
            view.addSubview(scrollView)
    
            scrollView.frame = view.frame
            scrollView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        }
    
    }
    

    ImageScrollView.swift

    import UIKit
    
    final class ImageScrollView: UIScrollView {
    
        private let imageView = UIImageView()
        override var frame: CGRect {
            didSet {
                if frame.size != oldValue.size { setZoomScale() }
            }
        }
    
        required init(image: UIImage) {
            super.init(frame: .zero)
    
            imageView.image = image
            imageView.sizeToFit()
            addSubview(imageView)
            contentSize = imageView.bounds.size
    
            contentInsetAdjustmentBehavior = .never // Adjust content according to safe area if necessary
            showsVerticalScrollIndicator = false
            showsHorizontalScrollIndicator = false
            alwaysBounceHorizontal = true
            alwaysBounceVertical = true
            delegate = self
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        // MARK: - Helper methods
    
        func setZoomScale() {
            let widthScale = frame.size.width / imageView.bounds.width
            let heightScale = frame.size.height / imageView.bounds.height
            let minScale = min(widthScale, heightScale)
            minimumZoomScale = minScale
            zoomScale = minScale
        }
    
    }
    
    extension ImageScrollView: UIScrollViewDelegate {
    
        func viewForZooming(in scrollView: UIScrollView) -> UIView? {
            return imageView
        }
    
        func scrollViewDidZoom(_ scrollView: UIScrollView) {
            let imageViewSize = imageView.frame.size
            let scrollViewSize = scrollView.bounds.size
            let verticalInset = imageViewSize.height < scrollViewSize.height ? (scrollViewSize.height - imageViewSize.height) / 2 : 0
            let horizontalInset = imageViewSize.width < scrollViewSize.width ? (scrollViewSize.width - imageViewSize.width) / 2 : 0
            scrollView.contentInset = UIEdgeInsets(top: verticalInset, left: horizontalInset, bottom: verticalInset, right: horizontalInset)
        }
    
    }
    

    #2. Using Auto Layout

    ViewController.swift

    import UIKit
    
    final class ViewController: UIViewController {
    
        private let scrollView = ImageScrollView(image: UIImage(named: "image")!)
    
        override func viewDidLoad() {
            view.backgroundColor = .black
            view.addSubview(scrollView)
    
            scrollView.translatesAutoresizingMaskIntoConstraints = false
            scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
            scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
            scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
            scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        }
    
        override func viewDidLayoutSubviews() {        
            scrollView.setZoomScale()
        }
    
    }
    

    ImageScrollView.swift

    import UIKit
    
    final class ImageScrollView: UIScrollView {
    
        private let imageView = UIImageView()
        private var imageViewBottomConstraint = NSLayoutConstraint()
        private var imageViewLeadingConstraint = NSLayoutConstraint()
        private var imageViewTopConstraint = NSLayoutConstraint()
        private var imageViewTrailingConstraint = NSLayoutConstraint()
    
        required init(image: UIImage) {
            super.init(frame: .zero)
    
            imageView.image = image
            imageView.sizeToFit()
            addSubview(imageView)
    
            imageView.translatesAutoresizingMaskIntoConstraints = false
            imageViewLeadingConstraint = imageView.leadingAnchor.constraint(equalTo: leadingAnchor)
            imageViewTrailingConstraint = imageView.trailingAnchor.constraint(equalTo: trailingAnchor)
            imageViewTopConstraint = imageView.topAnchor.constraint(equalTo: topAnchor)
            imageViewBottomConstraint = imageView.bottomAnchor.constraint(equalTo: bottomAnchor)
            NSLayoutConstraint.activate([imageViewLeadingConstraint, imageViewTrailingConstraint, imageViewTopConstraint, imageViewBottomConstraint])
    
            contentInsetAdjustmentBehavior = .never // Adjust content according to safe area if necessary
            showsVerticalScrollIndicator = false
            showsHorizontalScrollIndicator = false
            alwaysBounceHorizontal = true
            alwaysBounceVertical = true
            delegate = self
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        // MARK: - Helper methods
    
        func setZoomScale() {
            let widthScale = frame.size.width / imageView.bounds.width
            let heightScale = frame.size.height / imageView.bounds.height
            let minScale = min(widthScale, heightScale)
            minimumZoomScale = minScale
            zoomScale = minScale
        }
    
    }
    
    extension ImageScrollView: UIScrollViewDelegate {
    
        func viewForZooming(in scrollView: UIScrollView) -> UIView? {
            return imageView
        }
    
        func scrollViewDidZoom(_ scrollView: UIScrollView) {
            let yOffset = max(0, (bounds.size.height - imageView.frame.height) / 2)
            imageViewTopConstraint.constant = yOffset
            imageViewBottomConstraint.constant = yOffset
    
            let xOffset = max(0, (bounds.size.width - imageView.frame.width) / 2)
            imageViewLeadingConstraint.constant = xOffset
            imageViewTrailingConstraint.constant = xOffset
    
            layoutIfNeeded()
        }
    
    }
    

    Sources:

    • Github / ImageScrollView
    • raywenderlich.com / UIScrollView Tutorial: Getting Started
    0 讨论(0)
  • 2020-12-02 10:13

    Download this and this files. You'll need them to handle touches.

    Add to your view the scrollView delegate <UIScrollViewDelegate> and declare the outlets:

     @property (nonatomic, retain) IBOutlet UIScrollView *imageScrollView;
     @property (nonatomic, retain) UIImageView *imageView;
    

    Import the downloaded file inside the screen and do:

    #import "TapDetectingImageView.h"
    
    #define ZOOM_STEP 2.0
    @interface myView (UtilityMethods)
    - (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center;
    @end
    
    
    @implementation myView
    @synthesize imageScrollView, imageView;
    
    
    - (void)viewDidLoad
    {
    
        [super viewDidLoad];
    
        //Setting up the scrollView    
        imageScrollView.bouncesZoom = YES;
        imageScrollView.delegate = self;
        imageScrollView.clipsToBounds = YES;
    
        //Setting up the imageView
        imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"myImage.png"]];
        imageView.userInteractionEnabled = YES;
        imageView.autoresizingMask = ( UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin);
    
        //Adding the imageView to the scrollView as subView
        [imageScrollView addSubview:imageView];
        imageScrollView.contentSize = CGSizeMake(imageView.bounds.size.width, imageView.bounds.size.height);
        imageScrollView.decelerationRate = UIScrollViewDecelerationRateFast;
    
        //UITapGestureRecognizer set up
        UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
        UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];
        UITapGestureRecognizer *twoFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTwoFingerTap:)];
    
        [doubleTap setNumberOfTapsRequired:2];
        [twoFingerTap setNumberOfTouchesRequired:2];
    
        //Adding gesture recognizer
        [imageView addGestureRecognizer:doubleTap];
        [imageView addGestureRecognizer:twoFingerTap];
    
        [singleTap release];
        [doubleTap release];
        [twoFingerTap release];
    
        // calculate minimum scale to perfectly fit image width, and begin at that scale
        float minimumScale = 1.0;//This is the minimum scale, set it to whatever you want. 1.0 = default
        imageScrollView.maximumZoomScale = 4.0;
        imageScrollView.minimumZoomScale = minimumScale;
        imageScrollView.zoomScale = minimumScale;
        [imageScrollView setContentMode:UIViewContentModeScaleAspectFit];
        [imageView sizeToFit];
        [imageScrollView setContentSize:CGSizeMake(imageView.frame.size.width, imageView.frame.size.height)];
    
    
    
    }
    
    - (void)scrollViewDidZoom:(UIScrollView *)aScrollView {
        CGFloat offsetX = (imageScrollView.bounds.size.width > imageScrollView.contentSize.width)? 
        (imageScrollView.bounds.size.width - imageScrollView.contentSize.width) * 0.5 : 0.0;
        CGFloat offsetY = (imageScrollView.bounds.size.height > imageScrollView.contentSize.height)? 
        (imageScrollView.bounds.size.height - imageScrollView.contentSize.height) * 0.5 : 0.0;
        imageView.center = CGPointMake(imageScrollView.contentSize.width * 0.5 + offsetX, 
                                       imageScrollView.contentSize.height * 0.5 + offsetY);
    }
    
    - (void)viewDidUnload {
        self.imageScrollView = nil;
        self.imageView = nil;
    }
    
    
    
    #pragma mark UIScrollViewDelegate methods
    
    - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
        return imageView;
    }
    
    #pragma mark TapDetectingImageViewDelegate methods
    
    - (void)handleDoubleTap:(UIGestureRecognizer *)gestureRecognizer {
        // zoom in
        float newScale = [imageScrollView zoomScale] * ZOOM_STEP;
    
        if (newScale > self.imageScrollView.maximumZoomScale){
            newScale = self.imageScrollView.minimumZoomScale;
            CGRect zoomRect = [self zoomRectForScale:newScale withCenter:[gestureRecognizer locationInView:gestureRecognizer.view]];
    
            [imageScrollView zoomToRect:zoomRect animated:YES];
    
        }
        else{
    
            newScale = self.imageScrollView.maximumZoomScale;
            CGRect zoomRect = [self zoomRectForScale:newScale withCenter:[gestureRecognizer locationInView:gestureRecognizer.view]];
    
            [imageScrollView zoomToRect:zoomRect animated:YES];
        }
    }
    
    
    - (void)handleTwoFingerTap:(UIGestureRecognizer *)gestureRecognizer {
        // two-finger tap zooms out
        float newScale = [imageScrollView zoomScale] / ZOOM_STEP;
        CGRect zoomRect = [self zoomRectForScale:newScale withCenter:[gestureRecognizer locationInView:gestureRecognizer.view]];
        [imageScrollView zoomToRect:zoomRect animated:YES];
    }
    
    #pragma mark Utility methods
    
    - (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 = [imageScrollView frame].size.height / scale;
        zoomRect.size.width  = [imageScrollView 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;
    }
    

    Done!

    Basically what this code do is to add the imageView as subview of the imageScrollView.

    Then, it adds the TapDetecting class methods to the scrollView, in order to recognize the number of taps - the pinch the user do and add zoom functionalities.

    You can set the minimumScale of the image, if you leave 1.0 the image should be displayed as-it-is (if you set it a little bit lower it's being scaled), and the maximumZoomScale, i suggest you to leave it to 4, it's fine!

    Now, you can load images programmatically from there.

    The last thing you have to do is to insert a UIScrollView inside your xib file and link it to imageScrollView. You'll have the image at the perfect center, you can double tap on it to zoom, pinch to zoom as you set up in code.

    0 讨论(0)
提交回复
热议问题