1. 程式人生 > >scrollView實現圖片的縮小放大

scrollView實現圖片的縮小放大

之前實現view的放大縮小的時候是使用手勢,然後通過改變transform或者frame來實現,最近抽空看了下使用scrollView的實現方式

支援pinch手勢

先看一段官方文件的說明:

To support zooming, you must set a delegate for your scroll view. The delegate object must conform to the UIScrollViewDelegate protocol. In many cases, the delegate will be the scroll view’s controller class. That delegate class must implement the viewForZoomingInScrollView: method and return the view to zoom.

大致意思就是,是如果支援縮放 必須設定 scrollView的代理,該代理類必須實現viewForZoomingInScrollView:方法,以返回一個view進行縮放;

下面這段程式碼就返回了一個imageView來進行縮放

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

要指定使用者可以縮放的數量,可以設定minimumZoomScalemaximumZoomScale屬性的值,這兩個值最初都設定為1.0

- (void)viewDidLoad {
    [super viewDidLoad];
    self.scrollView.minimumZoomScale=0.5;
    self.scrollView.maximumZoomScale=6.0;
    self.scrollView.contentSize=CGSizeMake(1280, 960);
    self.scrollView.delegate=self;
   [self.scrollView addSubview:_imageView];
}

這樣我們就實現了imageView的一個縮放效果,

pinchZoom.gif

需要注意的是:如果想要通過捏合手勢來進行縮放,那至少要指定縮放因子(minimumZoomScalemaximumZoomScale,值不能相同)和實現viewForZoomingInScrollView:代理方法

以程式設計方式縮放

scrollView可能需要響應於諸如雙擊或其他輕擊手勢之類的觸控事件或者響應於除了捏合手勢之外的其他使用者動作而放大。為了做到這一點,UIScrollView提供了兩種方法的實現:setZoomScale:animated:zoomToRect:animated:

1. setZoomScale:animated:

  1. setZoomScale:animated:通過設定當前縮放比例為指定的值來縮放。該值必須是在minimumZoomScalemaximumZoomScale範圍內。animated指定是否有動畫。也可以直接設定scrollView的zoomScale屬性,直接設定屬性就相當於時animated為NO的setZoomScale:animated:方法;
  2. 通過該方法或者直接改變zoomScale屬性縮放檢視時,檢視的位置(origin)保持不變
- (IBAction)zoom:(id)sender {
    if (self.mainView.zoomScale > self.mainView.minimumZoomScale) {// 已經放大 現在縮小
        [self.mainView setZoomScale:self.mainView.minimumZoomScale animated:YES];
    }
    else {
        
        [self.mainView setZoomScale:self.mainView.maximumZoomScale animated:YES];
    }
    
    NSLog(@"self.imageView.center: %@  imageView origin: %@",NSStringFromCGPoint(self.imageView.center), NSStringFromCGPoint(self.imageView.frame.origin));
}

效果為

ProgrammaticallyZoom.gif

控制檯的列印資訊為

self.imageView.center: {207, 368} imageView origin: {138, 245.33333333333331}

self.imageView.center: {276, 490.66666666666663} imageView origin: {138, 245.33333333333329}

可以看到,imageView的origin是沒有改變的

2. zoomToRect:animated:

Zooms to a specific area of the content so that it is visible in the receiver.

放大到內容的特定區域,以便在receiver中可見。
引數解釋:

  • rect:A rectangle defining an area of the content view. The rectangle should be in the coordinate space of the view returned by viewForZoomingInScrollView:.
    定義內容檢視區域的矩形。 矩形應該位於viewForZoomingInScrollView:返回的檢視的座標空間中
  • animated:YES if the scrolling should be animated, NO if it should be immediate.
    animated引數決定了位置和縮放的變化是否會導致動畫發生

蘋果官方提供了一個示例,

/**
 該方法返回的矩形適合傳遞給zoomToRect:animated:方法。

 @param scrollView UIScrollView例項
 @param scale 新的縮放比例(通常zoomScale通過新增或乘以縮放量而從現有的縮放比例派生而來)
 @param center 放大縮小的中心點
 @return zoomRect 是以內容檢視為座標系
 */
- (CGRect)zoomRectForScrollView:(UIScrollView *)scrollView withScale:(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 = scrollView.frame.size.height / scale;
    zoomRect.size.width  = scrollView.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;
}
  • 當用戶完成縮放手勢或通過程式碼完成縮放時,會觸發scrollViewDidEndZooming:withView:atScale:代理事件。

通過點選進行縮放

通過點選進行縮放的時候, 我們可以通過tap手勢和touchesBegan:等方式, 在蘋果給出的示例中以touch的方式實現了點選縮放image

In order for your application to support tap to zoom functionality, you do not need to subclass theUIScrollViewclass. Instead you implement the required touch handling in the class for which theUIScrollViewdelegate methodviewForZoomingInScrollView:returns. That class will be responsible for tracking the number of fingers on the screen and the tap count. When it detects a single tap, a double tap, or a two-finger touch, it will respond accordingly. In the case of the double tap and two-finger touch, it should programmatically zoom the scroll view by the appropriate factor.

大致翻譯:
為了讓您的應用程式支援點選縮放功能,您不需要繼承UIScrollView該類。而是在UIScrollView委託方法viewForZoomingInScrollView:返回的類中實現所需的觸控處理 。該類將負責跟蹤螢幕上的手指數量和點選次數。當它檢測到單擊,雙擊或雙指觸控時,它將作出相應的響應。在雙擊和雙指觸控的情況下,應該以適當的因子以程式設計方式縮放scrollView

實現一個簡單的圖片放大縮小檢視功能

瀏覽.gif

主要有兩部分:

  1. show和dismiss時的過渡動畫
  2. 圖片的放大縮小

以上面的效果圖為例,我這裡是通過一個view來實現,在view中新增一個scrollView,scrollView上新增一個imageView來顯示圖片,並作為viewForZoomingInScrollView :的返回view。
.h檔案

- (instancetype)initWithOriginImage:(UIImage *)originImage highlightedImage:(UIImage *)highlightedImage fromRect:(CGRect)fromRect;

- (void)show;

- (void)dismiss;

在初始化的時候傳入一個普通圖片和一個高清圖片,以及圖片所在檢視(UIImageViewUIButton等)的frame;

動畫顯示圖片

- (void)showOriginImageWithAnimation
{
    self.imageView.frame = self.fromRect;
    if (self.originImage) {
        CGRect finalRect = [self getScaledFinalFrame];
        if (finalRect.size.height > getViewHeight(self.scrollView)) {
            self.scrollView.contentSize = CGSizeMake(getViewWidth(self.scrollView), finalRect.size.height);
        }
        self.alpha = 0.f;
        self.imageView.image = self.originImage;
        [UIView animateWithDuration:_animationDuration animations:^{
            self.imageView.frame = finalRect;
            self.alpha = 1.f;
        } completion:^(BOOL finished) {
            if (self.highlightedImage) {
                self.imageView.image = self.highlightedImage;
            }
        }];
    }
    else {
        self.imageView.frame = self.bounds;
        self.alpha = 0;
        if (self.highlightedImage) {
            self.imageView.image = self.highlightedImage;
        }
        [UIView animateWithDuration:_animationDuration animations:^{
            self.alpha = 1.f;
        } completion:nil];
    }
}

雙擊手勢,實現圖片的縮小和放大

- (void)doubleTapGesture:(UITapGestureRecognizer *)tap
{
    if (self.scrollView.zoomScale > _minimumZoomScale) {// 已經放大 現在縮小
        [self.scrollView setZoomScale:_minimumZoomScale animated:YES];
    }
    else {
        // 已經縮小 現在放大
        CGPoint point = [tap locationInView:self.scrollView];
//        [self zoomScrollView:self.scrollView toPoint:point withScale:_maximumZoomScale animated:YES];
        // 方法一 以point為中心點進行放大
        CGRect zoomRect = [self zoomRectForScrollView:self.scrollView withScale:_maximumZoomScale withCenter:point];
        [self.scrollView zoomToRect:zoomRect animated:YES];
        // 方法二 也可以通過這種方法 來放大 這種是直接放大 以scrollView的中心點
//        [self.scrollView setZoomScale:_maximumZoomScale animated:YES];
    }
}

消失動畫 也是單擊時呼叫的方法

- (void)dismiss
{
    CGRect frame = self.fromRect;
    CGFloat originX = self.scrollView.contentOffset.x + frame.origin.x;
    CGFloat originY = self.scrollView.contentOffset.y + frame.origin.y;
    frame.origin = CGPointMake(originX, originY);
    
    [UIView animateWithDuration:_animationDuration animations:^{
        self.imageView.frame = frame;
        self.alpha = 0.f;
    } completion:^(BOOL finished) {
        [self removeFromSuperview];
    }];
}

當然別忘了實現scrollView的代理方法

  • 返回imageView作為縮放檢視
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    return self.imageView;
}

縮放view的時候調整imageView的位置

// any zoom scale changes
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
    CGFloat scrollW = CGRectGetWidth(scrollView.frame);
    CGFloat scrollH = CGRectGetHeight(scrollView.frame);

    CGSize contentSize = scrollView.contentSize;
    CGFloat offsetX = scrollW > contentSize.width ? (scrollW - contentSize.width) * 0.5 : 0;
    CGFloat offsetY = scrollH > contentSize.height ? (scrollH - contentSize.height) * 0.5 : 0;

    CGFloat centerX = contentSize.width * 0.5 + offsetX;
    CGFloat centerY = contentSize.height * 0.5 + offsetY;

    self.imageView.center = CGPointMake(centerX, centerY);
}


轉載自連結:https://www.jianshu.com/p/3dfb0e409eb1