首页 文章

UIScrollView的中心内容较小时

提问于
浏览
135

我在 UIScrollView 里面有一个 UIImageView ,用于缩放和滚动 . 如果滚动视图的图像/内容大于滚动视图,则一切正常 . 但是,当图像变得小于滚动视图时,它会粘在滚动视图的左上角 . 我想让它保持中心,就像照片应用程序一样 .

有关保持 UIScrollView 内容较小的任何想法或示例?

我正在使用iPhone 3.0 .

以下代码几乎可以使用 . 如果在达到最小缩放级别后将其捏住,图像将返回到左上角 .

- (void)loadView {
    [super loadView];

    // set up main scroll view
    imageScrollView = [[UIScrollView alloc] initWithFrame:[[self view] bounds]];
    [imageScrollView setBackgroundColor:[UIColor blackColor]];
    [imageScrollView setDelegate:self];
    [imageScrollView setBouncesZoom:YES];
    [[self view] addSubview:imageScrollView];

    UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"WeCanDoIt.png"]];
    [imageView setTag:ZOOM_VIEW_TAG];
    [imageScrollView setContentSize:[imageView frame].size];
    [imageScrollView addSubview:imageView];

    CGSize imageSize = imageView.image.size;
    [imageView release];

    CGSize maxSize = imageScrollView.frame.size;
    CGFloat widthRatio = maxSize.width / imageSize.width;
    CGFloat heightRatio = maxSize.height / imageSize.height;
    CGFloat initialZoom = (widthRatio > heightRatio) ? heightRatio : widthRatio;

    [imageScrollView setMinimumZoomScale:initialZoom];
    [imageScrollView setZoomScale:1];

    float topInset = (maxSize.height - imageSize.height) / 2.0;
    float sideInset = (maxSize.width - imageSize.width) / 2.0;
    if (topInset < 0.0) topInset = 0.0;
    if (sideInset < 0.0) sideInset = 0.0;
    [imageScrollView setContentInset:UIEdgeInsetsMake(topInset, sideInset, -topInset, -sideInset)];
}

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
    return [imageScrollView viewWithTag:ZOOM_VIEW_TAG];
}

/************************************** NOTE **************************************/
/* The following delegate method works around a known bug in zoomToRect:animated: */
/* In the next release after 3.0 this workaround will no longer be necessary      */
/**********************************************************************************/
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {
    [scrollView setZoomScale:scale+0.01 animated:NO];
    [scrollView setZoomScale:scale animated:NO];
    // END Bug workaround

    CGSize maxSize = imageScrollView.frame.size;
    CGSize viewSize = view.frame.size;
    float topInset = (maxSize.height - viewSize.height) / 2.0;
    float sideInset = (maxSize.width - viewSize.width) / 2.0;
    if (topInset < 0.0) topInset = 0.0;
    if (sideInset < 0.0) sideInset = 0.0;
    [imageScrollView setContentInset:UIEdgeInsetsMake(topInset, sideInset, -topInset, -sideInset)];
}

24 回答

  • 1

    我有一个非常简单的解决方案!您只需在放大ScrollViewDelegate时更新子视图(imageview)的中心即可 . 如果缩放图像小于scrollview,则调整subview.center else center为(0,0) .

    - (void)scrollViewDidZoom:(UIScrollView *)scrollView 
    {
        UIView *subView = [scrollView.subviews objectAtIndex:0];
    
        CGFloat offsetX = MAX((scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5, 0.0);
        CGFloat offsetY = MAX((scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5, 0.0);
    
        subView.center = CGPointMake(scrollView.contentSize.width * 0.5 + offsetX, 
                                     scrollView.contentSize.height * 0.5 + offsetY);
    }
    
  • 1

    @EvelynCordner's answer是我的应用程序中效果最好的那个 . 比其他选项少得多的代码 .

    如果有人需要,这是Swift版本:

    func scrollViewDidZoom(_ scrollView: UIScrollView) {
        let offsetX = max((scrollView.bounds.width - scrollView.contentSize.width) * 0.5, 0)
        let offsetY = max((scrollView.bounds.height - scrollView.contentSize.height) * 0.5, 0)
        scrollView.contentInset = UIEdgeInsetsMake(offsetY, offsetX, 0, 0)
    }
    
  • 1

    好吧,过去两天我一直在争吵这个问题,终于找到了一个非常可靠的(迄今为止......)解决方案,我认为我应该分享它并为其他人带来一些痛苦 . :)如果您确实发现此解决方案的问题,请大声喊!

    我基本上已经了解了其他人的所有内容:搜索StackOverflow,Apple开发者论坛,查看了three20,ScrollingMadness,ScrollTestSuite等的代码 . 我尝试放大UIImageView框架,使用UIScrollView的偏移和/或插入来自ViewController等,但没有什么工作得很好(正如其他人也发现的那样) .

    在睡觉之后,我尝试了几个不同的角度:

    • 对UIImageView进行子类化以使其改变它's own size dynamically - this didn' t工作得很好 .

    • 对UIScrollView进行子类化,使其动态地改变它自己的contentOffset - 这对我来说似乎是一个胜利者 .

    使用这个子类化UIScrollView方法,我覆盖了contentOffset mutator,因此当图像缩放比视口小时,它不会设置{0,0} - 而是设置偏移量,使图像在视口中保持居中 . 到目前为止,似乎总是有效 . 我用宽,高,小和大的图像检查它,并没有“工作,但捏最小缩放打破它”问题 .

    我已经将一个示例项目上传到使用此解决方案的github,您可以在此处找到它:http://github.com/nyoron/NYOBetterZoom

  • 19

    此代码应适用于大多数iOS版本(并且已经过测试,可以在3.1版本上运行) .

    它基于photoscoller的Apple WWDC代码 .

    将以下内容添加到UIScrollView的子类中,并将tileContainerView替换为包含图像或切片的视图:

    - (void)layoutSubviews {
        [super layoutSubviews];
    
        // center the image as it becomes smaller than the size of the screen
        CGSize boundsSize = self.bounds.size;
        CGRect frameToCenter = tileContainerView.frame;
    
        // center horizontally
        if (frameToCenter.size.width < boundsSize.width)
            frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2;
        else
            frameToCenter.origin.x = 0;
    
        // center vertically
        if (frameToCenter.size.height < boundsSize.height)
            frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2;
        else
            frameToCenter.origin.y = 0;
    
        tileContainerView.frame = frameToCenter;
    }
    
  • 7

    对于更适合使用自动布局的滚动视图的解决方案,请使用滚动视图的内容插入,而不是更新滚动视图的子视图的帧 .

    - (void)scrollViewDidZoom:(UIScrollView *)scrollView
    {
        CGFloat offsetX = MAX((scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5, 0.0);
        CGFloat offsetY = MAX((scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5, 0.0);
    
        self.scrollView.contentInset = UIEdgeInsetsMake(offsetY, offsetX, 0.f, 0.f);
    }
    
  • 1

    目前我正在继承 UIScrollView 并重写 setContentOffset: 以根据 contentSize 调整偏移量 . 它适用于捏合和编程缩放 .

    @implementation HPCenteringScrollView
    
    - (void)setContentOffset:(CGPoint)contentOffset
    {
        const CGSize contentSize = self.contentSize;
        const CGSize scrollViewSize = self.bounds.size;
    
        if (contentSize.width < scrollViewSize.width)
        {
            contentOffset.x = -(scrollViewSize.width - contentSize.width) / 2.0;
        }
    
        if (contentSize.height < scrollViewSize.height)
        {
            contentOffset.y = -(scrollViewSize.height - contentSize.height) / 2.0;
        }
    
        [super setContentOffset:contentOffset];
    }
    
    @end
    

    除了简短和甜美之外,这段代码比@Erdemus解决方案产生更加平滑的缩放 . 您可以在RMGallery演示中看到它的运行情况 .

  • 1

    我花了一天时间来解决这个问题,最终实现了 scrollViewDidEndZooming:withView:atScale: 如下:

    - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {
        CGFloat screenWidth = [[UIScreen mainScreen] bounds].size.width;
        CGFloat screenHeight = [[UIScreen mainScreen] bounds].size.height;
        CGFloat viewWidth = view.frame.size.width;
        CGFloat viewHeight = view.frame.size.height;
    
        CGFloat x = 0;
        CGFloat y = 0;
    
        if(viewWidth < screenWidth) {
            x = screenWidth / 2;
        }
        if(viewHeight < screenHeight) {
            y = screenHeight / 2 ;
        }
    
        self.scrollView.contentInset = UIEdgeInsetsMake(y, x, y, x);
    }
    

    这可确保当图像小于屏幕时,周围仍有足够的空间,因此您可以将其放置在所需的确切位置 .

    (假设你的UIScrollView包含一个UIImageView来保存图像)

    基本上,这样做是检查你的图像视图的宽度/高度是否小于屏幕的宽度/高度,如果是这样,创建一个屏幕宽度/高度的一半的插入(如果你想要图像,你可能会更大走出屏幕边界) .

    请注意,由于这是一个UIScrollViewDelegate方法,因此要避免出现构建问题 .

  • 0

    Apple已向iphone开发者计划的所有成员发布了2010 WWDC会话视频 . 讨论的主题之一是他们如何创建照片应用程序!他们逐步构建一个非常相似的应用程序,并使所有代码免费提供 .

    它也不使用私有api . 由于非公开协议,我不能在此处放置任何代码,但这里是示例代码的链接下载 . 您可能需要登录才能获得访问权限 .

    http://connect.apple.com/cgi-bin/WebObjects/MemberSite.woa/wa/getSoftware?code=y&source=x&bundleID=20645

    并且,这是iTunes WWDC页面的链接:

    http://insideapple.apple.com/redir/cbx-cgi.do?v=2&la=en&lc=&a=kGSol9sgPHP%2BtlWtLp%2BEP%2FnxnZarjWJglPBZRHd3oDbACudP51JNGS8KlsFgxZto9X%2BTsnqSbeUSWX0doe%2Fzv%2FN5XV55%2FomsyfRgFBysOnIVggO%2Fn2p%2BiweDK%2F%2FmsIXj

  • 1

    好的,这个解决方案对我有用 . 我有一个 UIScrollView 的子类,它引用了它正在显示的 UIImageView . 每当 UIScrollView 缩放时,都会调整contentSize属性 . 在设定器中,我适当地缩放 UIImageView 并调整其中心位置 .

    -(void) setContentSize:(CGSize) size{
    CGSize lSelfSize = self.frame.size;
    CGPoint mid;
    if(self.zoomScale >= self.minimumZoomScale){
        CGSize lImageSize = cachedImageView.initialSize;
        float newHeight = lImageSize.height * self.zoomScale;
    
        if (newHeight < lSelfSize.height ) {
            newHeight = lSelfSize.height;
        }
        size.height = newHeight;
    
        float newWidth = lImageSize.width * self.zoomScale;
        if (newWidth < lSelfSize.width ) {
            newWidth = lSelfSize.width;
        }
        size.width = newWidth;
        mid = CGPointMake(size.width/2, size.height/2);
    
    }
    else {
        mid = CGPointMake(lSelfSize.width/2, lSelfSize.height/2);
    }
    
    cachedImageView.center = mid;
    [super  setContentSize:size];
    [self printLocations];
    NSLog(@"zoom %f setting size %f x %f",self.zoomScale,size.width,size.height);
    }
    

    Evertime我在 UIScrollView 上设置了图像我调整了它的大小 . scrollview中的 UIScrollView 也是我创建的自定义类 .

    -(void) resetSize{
        if (!scrollView){//scroll view is view containing imageview
            return;
        }
    
        CGSize lSize = scrollView.frame.size;
    
        CGSize lSelfSize = self.image.size; 
        float lWidth = lSize.width/lSelfSize.width;
        float lHeight = lSize.height/lSelfSize.height;
    
        // choose minimum scale so image width fits screen
        float factor  = (lWidth<lHeight)?lWidth:lHeight;
    
        initialSize.height = lSelfSize.height  * factor;
        initialSize.width = lSelfSize.width  * factor;
    
        [scrollView setContentSize:lSize];
        [scrollView setContentOffset:CGPointZero];
        scrollView.userInteractionEnabled = YES;
    }
    

    通过这两种方法,我可以拥有一个与照片应用程序一样的视图 .

  • 0

    您可以观察UIScrollView的 contentSize 属性(使用键值观察或类似),并在 contentSize 更改为小于滚动视图的大小时自动调整 contentInset .

  • 0

    一个优雅的方式来集中 UISCrollView 的内容就是这个 .

    将一个观察者添加到 UIScrollViewcontentSize 中,因此每次内容更改时都会调用此方法...

    [myScrollView addObserver:delegate 
                   forKeyPath:@"contentSize"
                      options:(NSKeyValueObservingOptionNew) 
                      context:NULL];
    

    现在用你的观察者方法:

    - (void)observeValueForKeyPath:(NSString *)keyPath   ofObject:(id)object   change:(NSDictionary *)change   context:(void *)context { 
    
        // Correct Object Class.
        UIScrollView *pointer = object;
    
        // Calculate Center.
        CGFloat topCorrect = ([pointer bounds].size.height - [pointer viewWithTag:100].bounds.size.height * [pointer zoomScale])  / 2.0 ;
                topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );
    
        topCorrect = topCorrect - (  pointer.frame.origin.y - imageGallery.frame.origin.y );
    
        // Apply Correct Center.
        pointer.center = CGPointMake(pointer.center.x,
                                     pointer.center.y + topCorrect ); }
    
    • 您应该更改 [pointer viewWithTag:100] . 替换为您的内容视图 UIView .

    • 同时更改指向窗口大小的 imageGallery .

    这将在每次更改大小时更正内容的中心 .

    NOTE: 这个内容不能很好地工作的唯一方法是使用 UIScrollView 的标准缩放功能 .

  • 0

    这是我对该问题的解决方案,对于scrollview中的任何类型的视图都可以正常工作 .

    -(void)scrollViewDidZoom:(__unused UIScrollView *)scrollView 
        {
        CGFloat top;
        CGFloat left;
        CGFloat bottom;
        CGFloat right;
    
        if (_scrollView.contentSize.width < scrollView.bounds.size.width) {
            DDLogInfo(@"contentSize %@",NSStringFromCGSize(_scrollView.contentSize));
    
            CGFloat width = (_scrollView.bounds.size.width-_scrollView.contentSize.width)/2.0;
    
            left = width;
            right = width;
    
    
        }else {
            left = kInset;
            right = kInset;
        }
    
        if (_scrollView.contentSize.height < scrollView.bounds.size.height) {
    
            CGFloat height = (_scrollView.bounds.size.height-_scrollView.contentSize.height)/2.0;
    
            top = height;
            bottom = height;
    
        }else {
            top = kInset;
            right = kInset;
        }
    
        _scrollView.contentInset = UIEdgeInsetsMake(top, left, bottom, right);
    
    
    
      if ([self.tiledScrollViewDelegate respondsToSelector:@selector(tiledScrollViewDidZoom:)])
      {
            [self.tiledScrollViewDelegate tiledScrollViewDidZoom:self];
      }
    }
    
  • 12

    这里有很多解决方案,但我冒险把它放在这里 . 这有两个原因:它不会影响缩放体验,就像更新正在进行的图像视图帧一样,并且它还尊重原始滚动视图插图(例如,在xib或storyboard中定义,以便优雅地处理半透明工具栏等) .

    首先,定义一个小帮手:

    CGSize CGSizeWithAspectFit(CGSize containerSize, CGSize contentSize) {
        CGFloat containerAspect = containerSize.width / containerSize.height,
                contentAspect = contentSize.width / contentSize.height;
    
        CGFloat scale = containerAspect > contentAspect
                        ? containerSize.height / contentSize.height
                        : containerSize.width / contentSize.width;
    
        return CGSizeMake(contentSize.width * scale, contentSize.height * scale);
    }
    

    要保留原始插图,请定义字段:

    UIEdgeInsets originalScrollViewInsets;
    

    在viewDidLoad中的某个地方填写它:

    originalScrollViewInsets = self.scrollView.contentInset;
    

    将UIImageView放入UIScrollView(假设UIImage本身位于loadedImage var中):

    CGSize containerSize = self.scrollView.bounds.size;
    containerSize.height -= originalScrollViewInsets.top + originalScrollViewInsets.bottom;
    containerSize.width -= originalScrollViewInsets.left + originalScrollViewInsets.right;
    
    CGSize contentSize = CGSizeWithAspectFit(containerSize, loadedImage.size);
    
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:(CGRect) { CGPointZero, contentSize }];
    imageView.autoresizingMask = UIViewAutoresizingNone;
    imageView.contentMode = UIViewContentModeScaleAspectFit;
    imageView.image = loadedImage;
    
    [self.scrollView addSubview:imageView];
    self.scrollView.contentSize = contentSize;
    
    [self centerImageViewInScrollView];
    

    scrollViewDidZoom:来自UIScrollViewDelegate的滚动视图:

    - (void)scrollViewDidZoom:(UIScrollView *)scrollView {
        if (scrollView == self.scrollView) {
            [self centerImageViewInScrollView];
        }
    }
    

    最后,以自身为中心:

    - (void)centerImageViewInScrollView {
        CGFloat excessiveWidth = MAX(0.0, self.scrollView.bounds.size.width - self.scrollView.contentSize.width),
                excessiveHeight = MAX(0.0, self.scrollView.bounds.size.height - self.scrollView.contentSize.height),
                insetX = excessiveWidth / 2.0,
                insetY = excessiveHeight / 2.0;
    
        self.scrollView.contentInset = UIEdgeInsetsMake(
                MAX(insetY, originalScrollViewInsets.top),
                MAX(insetX, originalScrollViewInsets.left),
                MAX(insetY, originalScrollViewInsets.bottom),
                MAX(insetX, originalScrollViewInsets.right)
        );
    }
    

    我还没有测试方向改变(即调整UIScrollView本身的适当反应),但修复它应该相对容易 .

  • 23

    您会发现Erdemus发布的解决方案确实有效,但是......在某些情况下,不会调用scrollViewDidZoom方法并且您的图像卡在左上角 . 一个简单的解决方案是在最初显示图像时显式调用该方法,如下所示:

    [self scrollViewDidZoom: scrollView];
    

    在许多情况下,您可能会两次调用此方法,但这是一个比本主题中的其他一些答案更清晰的解决方案 .

  • 37

    Apple的Photo Scroller示例完全符合您的要求 . 将它放在您的UIScrollView子类中,并将_zoomView更改为您的UIImageView .

    -(void)layoutSubviews{
      [super layoutSubviews];
      // center the zoom view as it becomes smaller than the size of the screen
      CGSize boundsSize = self.bounds.size;
      CGRect frameToCenter = self.imageView.frame;
      // center horizontally
      if (frameToCenter.size.width < boundsSize.width){
         frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2;
      }else{
        frameToCenter.origin.x = 0;
      }
      // center vertically
      if (frameToCenter.size.height < boundsSize.height){
         frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2;
      }else{
        frameToCenter.origin.y = 0;
      }
      self.imageView.frame = frameToCenter; 
    }
    

    Apple's Photo Scroller Sample Code

  • 25

    我这样做的方法是在层次结构中添加一个额外的视图:

    UIScrollView -> UIView -> UIImageView
    

    UIView 提供与 UIScrollView 相同的宽高比,并将 UIImageView 置于其中心 .

  • 225

    为了使动画流畅,请设置

    self.scrollview.bouncesZoom = NO;
    

    并使用此功能(使用this answer中的方法查找中心)

    - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale {
        [UIView animateWithDuration:0.2 animations:^{
            float offsetX = MAX((scrollView.bounds.size.width-scrollView.contentSize.width)/2, 0);
            float offsetY = MAX((scrollView.bounds.size.height-scrollView.contentSize.height)/2, 0);
            self.imageCoverView.center = CGPointMake(scrollView.contentSize.width*0.5+offsetX, scrollView.contentSize.height*0.5+offsetY);
        }];
    }
    

    这会产生弹跳效果,但不会事先涉及任何突然的动作 .

  • 0

    只是swift中的已批准答案,但没有使用委托进行子类化

    func centerScrollViewContents(scrollView: UIScrollView) {
        let contentSize = scrollView.contentSize
        let scrollViewSize = scrollView.frame.size;
        var contentOffset = scrollView.contentOffset;
    
        if (contentSize.width < scrollViewSize.width) {
            contentOffset.x = -(scrollViewSize.width - contentSize.width) / 2.0
        }
    
        if (contentSize.height < scrollViewSize.height) {
            contentOffset.y = -(scrollViewSize.height - contentSize.height) / 2.0
        }
    
        scrollView.setContentOffset(contentOffset, animated: false)
    }
    
    // UIScrollViewDelegate    
    func scrollViewDidZoom(scrollView: UIScrollView) {
        centerScrollViewContents(scrollView)
    }
    
  • 1

    如果您的内部imageView具有初始特定宽度(例如300),并且您只想将其宽度 only 放在缩小比其初始宽度小的位置,这也可能对您有所帮助 .

    func scrollViewDidZoom(scrollView: UIScrollView){
        if imageView.frame.size.width < 300{
            imageView.center.x = self.view.frame.width/2
        }
      }
    
  • 1

    这是我正在做这项工作的当前方式 . 它更好但仍然不完美 . 尝试设置:

    myScrollView.bouncesZoom = YES;
    

    修复 minZoomScale 时视图不居中的问题 .

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView
    {
    CGSize screenSize = [[self view] bounds].size;//[[UIScreen mainScreen] bounds].size;//
    CGSize photoSize = [yourImage size];
    CGFloat topInset = (screenSize.height - photoSize.height * [myScrollView zoomScale]) / 2.0;
    CGFloat sideInset = (screenSize.width - photoSize.width * [myScrollView zoomScale]) / 2.0;
    
    if (topInset < 0.0)
    { topInset = 0.0; }
    if (sideInset < 0.0)
    { sideInset = 0.0; } 
    [myScrollView setContentInset:UIEdgeInsetsMake(topInset, sideInset, -topInset, -sideInset)];
    ApplicationDelegate *appDelegate = (ApplicationDelegate *)[[UIApplication sharedApplication] delegate];
    
    CGFloat scrollViewHeight; //Used later to calculate the height of the scrollView
    if (appDelegate.navigationController.navigationBar.hidden == YES) //If the NavBar is Hidden, set scrollViewHeight to 480
    { scrollViewHeight = 480; }
    if (appDelegate.navigationController.navigationBar.hidden == NO) //If the NavBar not Hidden, set scrollViewHeight to 360
    { scrollViewHeight = 368; }
    
    imageView.frame = CGRectMake(0, 0, CGImageGetWidth(yourImage)* [myScrollView zoomScale], CGImageGetHeight(yourImage)* [myScrollView zoomScale]);
    
    [imageView setContentMode:UIViewContentModeCenter];
    }
    

    此外,我执行以下操作以防止图像在缩小后粘在一侧 .

    - (void) scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {
    myScrollView.frame = CGRectMake(0, 0, 320, 420);
     //put the correct parameters for your scroll view width and height above
    }
    
  • 20

    好的,我想我找到了一个很好的解决方案 . 诀窍是不断重新调整 imageView's 帧 . 我发现这比不断调整 contentInsetscontentOffSets 要好得多 . 我不得不添加一些额外的代码来容纳纵向和横向图像 .

    这是代码:

    - (void) scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {
    
    CGSize screenSize = [[self view] bounds].size;
    
    if (myScrollView.zoomScale <= initialZoom +0.01) //This resolves a problem with the code not working correctly when zooming all the way out.
    {
        imageView.frame = [[self view] bounds];
        [myScrollView setZoomScale:myScrollView.zoomScale +0.01];
    }
    
    if (myScrollView.zoomScale > initialZoom)
    {
        if (CGImageGetWidth(temporaryImage.CGImage) > CGImageGetHeight(temporaryImage.CGImage)) //If the image is wider than tall, do the following...
        {
            if (screenSize.height >= CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale]) //If the height of the screen is greater than the zoomed height of the image do the following...
            {
                imageView.frame = CGRectMake(0, 0, 320*(myScrollView.zoomScale), 368);
            }
            if (screenSize.height < CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale]) //If the height of the screen is less than the zoomed height of the image do the following...
            {
                imageView.frame = CGRectMake(0, 0, 320*(myScrollView.zoomScale), CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale]);
            }
        }
        if (CGImageGetWidth(temporaryImage.CGImage) < CGImageGetHeight(temporaryImage.CGImage)) //If the image is taller than wide, do the following...
        {
            CGFloat portraitHeight;
            if (CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale] < 368)
            { portraitHeight = 368;}
            else {portraitHeight = CGImageGetHeight(temporaryImage.CGImage) * [myScrollView zoomScale];}
    
            if (screenSize.width >= CGImageGetWidth(temporaryImage.CGImage) * [myScrollView zoomScale]) //If the width of the screen is greater than the zoomed width of the image do the following...
            {
                imageView.frame = CGRectMake(0, 0, 320, portraitHeight);
            }
            if (screenSize.width < CGImageGetWidth (temporaryImage.CGImage) * [myScrollView zoomScale]) //If the width of the screen is less than the zoomed width of the image do the following...
            {
                imageView.frame = CGRectMake(0, 0, CGImageGetWidth(temporaryImage.CGImage) * [myScrollView zoomScale], portraitHeight);
            }
        }
        [myScrollView setZoomScale:myScrollView.zoomScale -0.01];
    }
    
  • 1

    只是禁用分页,所以它会工作正常:

    scrollview.pagingEnabled = NO;
    
  • 2

    我有同样的问题 . 这是我如何解决的

    应该将此代码作为 scrollView:DidScroll: 的结果调用

    CGFloat imageHeight = self.imageView.frame.size.width * self.imageView.image.size.height / self.imageView.image.size.width;
    BOOL imageSmallerThanContent = (imageHeight < self.scrollview.frame.size.height) ? YES : NO;
    CGFloat topOffset = (self.imageView.frame.size.height - imageHeight) / 2;
    
    // If image is not large enough setup content offset in a way that image is centered and not vertically scrollable
    if (imageSmallerThanContent) {
         topOffset = topOffset - ((self.scrollview.frame.size.height - imageHeight)/2);
    }
    
    self.scrollview.contentInset = UIEdgeInsetsMake(topOffset * -1, 0, topOffset * -1, 0);
    
  • 1

    虽然这个问题有点陈旧但问题仍然存在 . 我在 Xcode 7 中通过将最上面的项目(在本例中为 topLabel )的垂直空间约束设置为superViews( scrollView )顶部 IBOutlet 然后每次内容根据scrollView的子视图的高度更改时重新计算其常量来解决它( topLabelbottomLabel ) .

    class MyViewController: UIViewController {
    
        @IBOutlet weak var scrollView: UIScrollView!
        @IBOutlet weak var topLabel: UILabel!
        @IBOutlet weak var bottomLabel: UILabel!
        @IBOutlet weak var toTopConstraint: NSLayoutConstraint!
    
        override func viewDidLayoutSubviews() {
            let heightOfScrollViewContents = (topLabel.frame.origin.y + topLabel.frame.size.height - bottomLabel.frame.origin.y)
            // In my case abs() delivers the perfect result, but you could also check if the heightOfScrollViewContents is greater than 0.
            toTopConstraint.constant = abs((scrollView.frame.height - heightOfScrollViewContents) / 2)
        }
    
        func refreshContents() {
            // Set the label's text …
    
            self.view.layoutIfNeeded()
        }
    }
    

相关问题