IOS:在滚动视图中添加图像视图以进行缩放

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11318845/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 19:06:58  来源:igfitidea点击:

IOS: add imageview in a scrollview to have zoom

iosuiscrollviewuiimageviewuiimage

提问by cyclingIsBetter

I want to set a UIImageView with a UIImageand put this imageview inside a UIScrollViewto obtain a zoom of this image; and I want this UIImageViewand UIScrollViewto fit in the rect at the center of the view...is it possible?

我想用 a 设置一个 UIImageViewUIImage并将这个图像视图放在 a 中UIScrollView以获得该图像的缩放;我想要这个UIImageView并且UIScrollView适合视图中心的矩形......这可能吗?

回答by Justin Paulson

  1. Set your view controller up as a <UIScrollViewDelegate>
  2. Draw your UIScrollViewthe 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 UIImageViewin the UIScrollViewand set it up with whatever image you want. Make it the same size as the UIScrollView.
  5. Ctrl + drag form you UIImageViewto the .hof your View controller to create an IBOutletfor 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.

  1. 将您的视图控制器设置为 <UIScrollViewDelegate>
  2. UIScrollView为视图中心的矩形绘制所需的大小。将检查器中的最大缩放设置为大于 1 的值。例如 4 或 10。
  3. 右键单击滚动视图并将委托连接到您的视图控制器。
  4. 绘制您UIImageViewUIScrollView图像并使用您想要的任何图像进行设置。使其大小与UIScrollView.
  5. 按Ctrl +拖动表格,您UIImageView.h您的视图控制器创建的IBOutletUIImageView,把它一些聪明像imageView
  6. 添加此代码:

    -(UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView
    {
        return self.imageView;
    }
    
  7. 运行该应用程序并捏合和平移直到您满意为止。

回答by Phillip

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

下载这个这个文件。您将需要它们来处理触摸。

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

将 scrollView 委托添加到您的视图中<UIScrollViewDelegate>并声明插座:

 @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 imageViewas subview of the imageScrollView.

基本上这代码做的是添加imageView为子视图imageScrollView

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

然后,它将TapDetecting类方法添加到 scrollView,以识别点击次数 - 用户所做的捏合并添加缩放功能。

You can set the minimumScaleof the image, if you leave 1.0the 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!

您可以设置minimumScale图像的 ,如果您保留1.0图像应按原样显示(如果您将其设置得低一点,它会被缩放),而maximumZoomScale,我建议您将其保留为 4,这很好!

Now, you can load images programmatically from there.

现在,您可以从那里以编程方式加载图像。

The last thing you have to do is to insert a UIScrollViewinside 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.

您需要做的最后一件事是UIScrollView在您的 xib 文件中插入一个并将其链接到imageScrollView. 您将在完美的中心放置图像,您可以在代码中设置时双击它进行缩放,捏合缩放。

回答by Imanou Petit

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

对于 Swift 4 和 iOS 11,您可以使用以下两种解决方案之一来解决您的问题。



#1. Using insets

#1. 使用插图

ViewController.swift

视图控制器.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

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

#2. 使用自动布局

ViewController.swift

视图控制器.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

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:

资料来源:

回答by Delete

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/.

我编写了一个示例应用程序,它也支持 AutoLayout 和 Storyboards 来演示这种行为。我希望它可以节省每个人试图解决这个问题的时间:http: //rexstjohn.com/facebook-like-ios-photo-modal-gallery-swipe-gestures/