web-dev-qa-db-ja.com

IOS:スクロールビューに画像ビューを追加してズームする

UIImageViewにUIImageを設定し、この画像ビューをUIScrollView内に配置して、この画像のズームを取得します。そして、このUIImageViewUIScrollViewがビューの中央の長方形に収まるようにします...それは可能ですか?

29
CrazyDev
  1. View Controllerを_<UIScrollViewDelegate>_として設定します
  2. UIScrollViewを、ビューの中心にある長方形に必要なサイズで描画します。インスペクターの最大ズームを1より大きい値に設定します。4または10など。
  3. スクロールビューを右クリックして、デリゲートをビューコントローラーに接続します。
  4. UIImageViewUIScrollViewを描画し、必要な画像を設定します。 UIScrollViewと同じサイズにします。
  5. Ctrlキーを押しながらUIImageViewをViewコントローラーの_.h_にドラッグして、IBOutletUIImageViewを作成し、imageViewのような巧妙な名前を付けます。
  6. このコードを追加してください:

    _-(UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView
    {
        return self.imageView;
    }
    _
  7. アプリを実行して、思いっきりコンテンツをピンチしてパンします。

90
Justin Paulson

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にリンクすることです。画像を完璧な中央に配置します。コードをセットアップするときに、ダブルタップしてズームしたり、ピンチしてズームしたりできます。

29
Phillip

Swift 4およびiOS 11では、問題を解決するために次の2つのソリューションのいずれかを使用できます。


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

}

ソース:

5
Imanou Petit

この動作を示すためにAutoLayoutとStoryboardsもサポートするサンプルアプリケーションを作成しました。これを理解するための時間を節約できることを願っています: http://rexstjohn.com/facebook-like-ios-photo-modal-gallery-swipe-gestures/

3
Delete