38

我想要一个带有图像内容视图的滚动视图。图像实际上是比屏幕大得多的地图。地图最初应该位于滚动视图的中心,就像当您将 iPhone 转为横向时照片应用程序中的照片一样。

替代文字

我没有设法让地图在中心同时正确缩放和滚动。如果地图图像从屏幕顶部开始(纵向),则代码如下所示:

- (void)loadView {
    mapView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"map.jpg"]];
    CGFloat mapHeight = MAP_HEIGHT * SCREEN_WIDTH / MAP_WIDTH;
    mapView.frame = CGRectMake(0, 0, SCREEN_WIDTH, mapHeight);
    scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
    scrollView.delegate = self;
    scrollView.contentSize = mapView.frame.size;
    scrollView.maximumZoomScale = MAP_WIDTH / SCREEN_WIDTH;
    scrollView.minimumZoomScale = 1;
    [scrollView addSubview:mapView];
    self.view = scrollView;
}

当我将图像框架移动到中心时,图像仅从其框架的顶部向下增长。我尝试使用 mapView 转换,动态更改 imageView 的框架。到目前为止,没有什么对我有用。

4

11 回答 11

40

这段代码应该可以在大多数版本的 iOS 上运行(并且已经过测试可以在 3.1 以上版本上运行)。

它基于 Jonah 的回答中提到的 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;
}
于 2010-08-13T16:42:33.500 回答
22

这是我要考虑的,其中的解决方案与苹果的照片应用程序完全一样。我一直在使用以下解决方案:

-(void) scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale

重新定位,但我不喜欢那个解决方案,因为在缩放完成后,它会反弹然后快速“跳”到中心,这非常不性感。事实证明,如果您几乎执行完全相同的逻辑,但在此委托函数中:

-(void)scrollViewDidZoom:(UIScrollView *)pScrollView

它都以居中开始,当您缩小时它保持居中:

-(void)scrollViewDidZoom:(UIScrollView *)pScrollView {
CGRect innerFrame = imageView.frame;
CGRect scrollerBounds = pScrollView.bounds;

if ( ( innerFrame.size.width < scrollerBounds.size.width ) || ( innerFrame.size.height < scrollerBounds.size.height ) )
{
    CGFloat tempx = imageView.center.x - ( scrollerBounds.size.width / 2 );
    CGFloat tempy = imageView.center.y - ( scrollerBounds.size.height / 2 );
    CGPoint myScrollViewOffset = CGPointMake( tempx, tempy);

    pScrollView.contentOffset = myScrollViewOffset;

}

UIEdgeInsets anEdgeInset = { 0, 0, 0, 0};
if ( scrollerBounds.size.width > innerFrame.size.width )
{
    anEdgeInset.left = (scrollerBounds.size.width - innerFrame.size.width) / 2;
    anEdgeInset.right = -anEdgeInset.left;  // I don't know why this needs to be negative, but that's what works
}
if ( scrollerBounds.size.height > innerFrame.size.height )
{
    anEdgeInset.top = (scrollerBounds.size.height - innerFrame.size.height) / 2;
    anEdgeInset.bottom = -anEdgeInset.top;  // I don't know why this needs to be negative, but that's what works
}
pScrollView.contentInset = anEdgeInset;
}

'imageView' 是UIImageView你正在使用的地方。

于 2010-02-03T02:51:58.273 回答
7

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

于 2010-06-20T19:48:36.720 回答
2

我怀疑你需要设置UIScrollView's contentOffset

于 2009-03-12T19:16:05.013 回答
1

我希望它是那么简单。我在网上做了一些研究,发现这不仅仅是我的问题,而且很多人都在为同样的问题而苦苦挣扎,不仅在 iPhone 上,而且在 Apple 的桌面 Cocoa 上也是如此。请参阅以下链接:

http://www.iphonedevsdk.com/forum/iphone-sdk-development/5740-uiimageview-uiscrollview.html
所描述的解决方案是基于图像的 UIViewContentModeScaleAspectFit 属性,但不幸的是它不能很好地工作。图像是居中并正常增长,但弹跳区域似乎比图片大得多。

这家伙也没有得到答案:
http ://discussions.apple.com/thread.jspa?messageID=8322675

最后,Apple 桌面 Cocoa 上的同样问题:http:
//www.cocoadev.com/index.pl?
CenteringInsideNSScrollView 我想该解决方案有效,但它基于 NSClipView,它不在 iPhone 上......

有人有一些适用于 iPhone 的解决方案吗?

于 2009-03-13T07:29:54.670 回答
1

这对我有用:

- (void) scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {
CGFloat tempx = view.center.x-160;
CGFloat tempy = view.center.y-160;
myScrollViewOffset = CGPointMake(tempx,tempy);

}

其中 160 是您的UIScrollView.

然后稍后我将 contentoffset 设置为此处捕获的内容。

于 2009-03-31T08:15:00.383 回答
0

一种将内容居中的优雅方式UISCrollView是这样。

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

[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指向您的窗口大小。

每次他的大小改变时,这将纠正内容的中心。

注意:此内容不能很好地工作的唯一方法是使用UIScrollView.

于 2009-11-03T17:14:45.793 回答
0

注意:这种方法有点工作。如果图像小于 imageView,它将部分滚动到屏幕外。没什么大不了的,但也不如照片应用程序那么好。

首先,重要的是要了解我们正在处理 2 个视图,其中包含图像的图像视图和包含图像视图的滚动视图。所以,首先将imageview设置为屏幕大小:

 [myImageView setFrame:self.view.frame];

然后,在 imageview 中居中您的图像:

 myImageView.contentMode = UIViewContentModeCenter;

这是我的整个代码:

- (void)viewDidLoad {
AppDelegate *appDelegate = (pAppDelegate *)[[UIApplication sharedApplication] delegate];
 [super viewDidLoad];
 NSString *Path = [[NSBundle mainBundle] bundlePath];
 NSString *ImagePath = [Path stringByAppendingPathComponent:(@"data: %@", appDelegate.MainImageName)];
 UIImage *tempImg = [[UIImage alloc] initWithContentsOfFile:ImagePath];
 [imgView setImage:tempImg];

 myScrollView = [[UIScrollView alloc] initWithFrame:[[self view] bounds]];
 [myScrollView addSubview:myImageView];

//Set ScrollView Appearance
 [myScrollView setBackgroundColor:[UIColor blackColor]];
 myScrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;

//Set Scrolling Prefs
 myScrollView.bounces = YES;
 myScrollView.delegate = self;
 myScrollView.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
 [myScrollView setCanCancelContentTouches:NO];
 [myScrollView setScrollEnabled:YES];


//Set Zooming Prefs
 myScrollView.maximumZoomScale = 3.0;
 myScrollView.minimumZoomScale = CGImageGetWidth(tempImg.CGImage)/320;
 myScrollView.zoomScale = 1.01; //Added the .01 to enable scrolling immediately upon view load.
 myScrollView.bouncesZoom = YES;


 [myImageView setFrame:self.view.frame];//rect];// .frame.size.height = imageHeight;
 myImageView.contentMode = UIViewContentModeCenter;
 self.view = myScrollView;
 [tempImg release];
 }
于 2009-09-08T02:14:18.973 回答
0

好的,我想我已经找到了一个很好的解决这个问题的方法。诀窍是不断地重新调整 imageView 的框架。我发现这比不断调整 contentInsets 或 contentOffSets 好得多。我不得不添加一些额外的代码来容纳纵向和横向图像。

这是代码:

- (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];
}
于 2009-10-04T02:16:27.800 回答
0

在对我有用的 Monotouch 中。

this._scroll.ScrollRectToVisible(new RectangleF(_scroll.ContentSize.Width/2, _scroll.ContentSize.Height/2,1,1),false);
于 2012-08-08T14:45:59.493 回答
0

这是另一种解决方案,类似于@JosephH 的答案,但这个解决方案考虑了图像的实际尺寸。因此,当用户平移/缩放时,屏幕上的空白永远不会超过所需。这是一个常见问题,例如在纵向屏幕上显示横向图像时。当整个图像显示在屏幕上时(Aspect Fit),图像上方和下方都会有空白。然后,在放大时,其他解决方案会将该空白视为图像的一部分,因为它位于 imageView 中。它们会让您将大部分图像平移到屏幕外,只留下可见的空白。这对用户来说看起来很糟糕。

使用此类,您确实需要将它正在使用的 imageView 传递给它。我很想让它自动检测,但这更快,你想要在layoutSubviews方法中获得的所有速度。

注意:按原样,这要求不为 scrollView 启用 AutoLayout。

//
//  CentringScrollView.swift
//  Cerebral Gardens
//
//  Created by Dave Wood
//  Copyright © 2016 Cerebral Gardens Inc. All rights reserved.
//

import UIKit

class CentringScrollView: UIScrollView {

    var imageView: UIImageView?

    override func layoutSubviews() {
        super.layoutSubviews()

        guard let superview = superview else { return }
        guard let imageView = imageView else { return }
        guard let image = imageView.image else { return }

        var frameToCentre = imageView.frame

        let imageWidth = image.size.width
        let imageHeight = image.size.height

        let widthRatio = superview.bounds.size.width / imageWidth
        let heightRatio = superview.bounds.size.height / imageHeight

        let minRatio = min(widthRatio, heightRatio, 1.0)

        let effectiveImageWidth = minRatio * imageWidth * zoomScale
        let effectiveImageHeight = minRatio * imageHeight * zoomScale

        contentSize = CGSize(width: max(effectiveImageWidth, bounds.size.width), height: max(effectiveImageHeight, bounds.size.height))

        frameToCentre.origin.x = (contentSize.width - frameToCentre.size.width) / 2
        frameToCentre.origin.y = (contentSize.height - frameToCentre.size.height) / 2

        imageView.frame = frameToCentre
    }
}
于 2016-05-05T09:56:02.867 回答