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

Posted

技术标签:

【中文标题】IOS:在滚动视图中添加图像视图以进行缩放【英文标题】:IOS: add imageview in a scrollview to have zoom 【发布时间】:2012-07-03 20:40:21 【问题描述】:

我想设置一个带有UIImage 的UIImageView 并将这个imageview 放在UIScrollView 中以获得这个图像的缩放; 我希望这个UIImageViewUIScrollView 适合视图中心的矩形...有可能吗?

【问题讨论】:

所以您希望图像通过捏合进行缩放,但滚动视图中的其他所有内容都保持不变? 是的,这绝对是可能的。你有没有尝试过任何东西?您所描述的大部分内容都可以在界面构建器/故事板中完成 【参考方案1】:
    将您的视图控制器设置为<UIScrollViewDelegate>UIScrollView 绘制成视图中心矩形所需的大小。将检查器中的最大缩放设置为大于 1 的值。例如 4 或 10。 右键单击滚动视图并将代理连接到您的视图控制器。 在UIScrollView 中画出您的UIImageView,并使用您想要的任何图像进行设置。使其大小与UIScrollView 相同。 Ctrl + 将 UIImageView 拖到 View 控制器的 .h 上,为 UIImageView 创建一个 IBOutlet,称之为 imageView 之类的聪明的东西。

    添加此代码:

    -(UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView
    
        return self.imageView;
    
    

    运行应用程序并捏合和平移,直到心满意足为止。

【讨论】:

你能以编程方式举一个例子吗? 迄今为止我找到的最简单、最清晰的解决方案 @Justin Paulson 我们可以将缩小限制为图像大小吗?我不希望用户缩小图像大小。你能帮帮我吗?【参考方案2】:

下载this 和this 文件。你需要它们来处理触摸。

将 scrollView 委托 <UIScrollViewDelegate> 添加到您的视图并声明网点:

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

将下载的文件导入屏幕并执行:

#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;

完成!

基本上,这段代码的作用是将imageView 添加为imageScrollView 的子视图。

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

您可以设置图像的minimumScale,如果您离开1.0,图像应按原样显示(如果您将其设置得稍微低一点,则会被缩放),而maximumZoomScale,我建议你留到4,没关系!

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

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

【讨论】:

这就像一个烹饪食谱。步骤是正确的,但您没有解释他为什么要这样做。这最终会帮助他和其他人更多。 这基本上是我在我的应用程序中使用的代码。我来解释一下 不要误会我的意思——代码很好,但为什么也很重要。否则他将不知道如何解决类似的问题。 当然,你是对的!我只是认为代码中的 cmets 是不言自明的!不过,谢谢你注意到我。 双击时,缩放图像时,它会像滚动视图一样缩放并超出屏幕。如何解决?【参考方案3】:

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


#1。使用插图

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。使用自动布局

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()
    



来源:

Github / ImageScrollView raywenderlich.com / UIScrollView Tutorial: Getting Started

【讨论】:

【参考方案4】:

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

【讨论】:

以上是关于IOS:在滚动视图中添加图像视图以进行缩放的主要内容,如果未能解决你的问题,请参考以下文章

iOS UIScrollView捏缩放添加空白

在 ios 的滚动视图中绘制缩放的图像视图?

ios - 滚动到结束时滚动视图缩放,如 Fancy

按下缩放按钮时如何缩放滚动视图的图像?

在 iPhone 中使用缩放图像翻转滚动视图

Xcode:在滚动视图中缩放图像