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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章