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
IOS: add imageview in a scrollview to have zoom
提问by cyclingIsBetter
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 UIImageView
and UIScrollView
to fit in the rect at the center of the view...is it possible?
我想用 a 设置一个 UIImageViewUIImage
并将这个图像视图放在 a 中UIScrollView
以获得该图像的缩放;我想要这个UIImageView
并且UIScrollView
适合视图中心的矩形......这可能吗?
回答by Justin Paulson
- Set your view controller up as a
<UIScrollViewDelegate>
- 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. - Right click on the scroll view and connect the delegate to your view controller.
- Draw your
UIImageView
in theUIScrollView
and set it up with whatever image you want. Make it the same size as theUIScrollView
. - Ctrl + drag form you
UIImageView
to the.h
of your View controller to create anIBOutlet
for theUIImageView
, call it something clever likeimageView
. Add this code:
-(UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView { return self.imageView; }
Run the app and pinch and pan til your heart's content.
- 将您的视图控制器设置为
<UIScrollViewDelegate>
UIScrollView
为视图中心的矩形绘制所需的大小。将检查器中的最大缩放设置为大于 1 的值。例如 4 或 10。- 右键单击滚动视图并将委托连接到您的视图控制器。
- 绘制您
UIImageView
的UIScrollView
图像并使用您想要的任何图像进行设置。使其大小与UIScrollView
. - 按Ctrl +拖动表格,您
UIImageView
给.h
您的视图控制器创建的IBOutlet
对UIImageView
,把它一些聪明像imageView
。 添加此代码:
-(UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView { return self.imageView; }
运行该应用程序并捏合和平移直到您满意为止。
回答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 imageView
as subview of the imageScrollView
.
基本上这代码做的是添加imageView
为子视图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.
然后,它将TapDetecting
类方法添加到 scrollView,以识别点击次数 - 用户所做的捏合并添加缩放功能。
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!
您可以设置minimumScale
图像的 ,如果您保留1.0
图像应按原样显示(如果您将其设置得低一点,它会被缩放),而maximumZoomScale
,我建议您将其保留为 4,这很好!
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.
您需要做的最后一件事是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/。