我在 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 回答
我有一个非常简单的解决方案!您只需在放大ScrollViewDelegate时更新子视图(imageview)的中心即可 . 如果缩放图像小于scrollview,则调整subview.center else center为(0,0) .
@EvelynCordner's answer是我的应用程序中效果最好的那个 . 比其他选项少得多的代码 .
如果有人需要,这是Swift版本:
好吧,过去两天我一直在争吵这个问题,终于找到了一个非常可靠的(迄今为止......)解决方案,我认为我应该分享它并为其他人带来一些痛苦 . :)如果您确实发现此解决方案的问题,请大声喊!
我基本上已经了解了其他人的所有内容:搜索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
此代码应适用于大多数iOS版本(并且已经过测试,可以在3.1版本上运行) .
它基于photoscoller的Apple WWDC代码 .
将以下内容添加到UIScrollView的子类中,并将tileContainerView替换为包含图像或切片的视图:
对于更适合使用自动布局的滚动视图的解决方案,请使用滚动视图的内容插入,而不是更新滚动视图的子视图的帧 .
目前我正在继承
UIScrollView
并重写setContentOffset:
以根据contentSize
调整偏移量 . 它适用于捏合和编程缩放 .除了简短和甜美之外,这段代码比@Erdemus解决方案产生更加平滑的缩放 . 您可以在RMGallery演示中看到它的运行情况 .
我花了一天时间来解决这个问题,最终实现了 scrollViewDidEndZooming:withView:atScale: 如下:
这可确保当图像小于屏幕时,周围仍有足够的空间,因此您可以将其放置在所需的确切位置 .
(假设你的UIScrollView包含一个UIImageView来保存图像)
基本上,这样做是检查你的图像视图的宽度/高度是否小于屏幕的宽度/高度,如果是这样,创建一个屏幕宽度/高度的一半的插入(如果你想要图像,你可能会更大走出屏幕边界) .
请注意,由于这是一个UIScrollViewDelegate方法,因此要避免出现构建问题 .
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
好的,这个解决方案对我有用 . 我有一个
UIScrollView
的子类,它引用了它正在显示的UIImageView
. 每当UIScrollView
缩放时,都会调整contentSize属性 . 在设定器中,我适当地缩放UIImageView
并调整其中心位置 .Evertime我在
UIScrollView
上设置了图像我调整了它的大小 . scrollview中的UIScrollView
也是我创建的自定义类 .通过这两种方法,我可以拥有一个与照片应用程序一样的视图 .
您可以观察UIScrollView的
contentSize
属性(使用键值观察或类似),并在contentSize
更改为小于滚动视图的大小时自动调整contentInset
.一个优雅的方式来集中
UISCrollView
的内容就是这个 .将一个观察者添加到
UIScrollView
的 contentSize 中,因此每次内容更改时都会调用此方法...现在用你的观察者方法:
您应该更改
[pointer viewWithTag:100]
. 替换为您的内容视图UIView
.同时更改指向窗口大小的
imageGallery
.这将在每次更改大小时更正内容的中心 .
NOTE: 这个内容不能很好地工作的唯一方法是使用
UIScrollView
的标准缩放功能 .这是我对该问题的解决方案,对于scrollview中的任何类型的视图都可以正常工作 .
这里有很多解决方案,但我冒险把它放在这里 . 这有两个原因:它不会影响缩放体验,就像更新正在进行的图像视图帧一样,并且它还尊重原始滚动视图插图(例如,在xib或storyboard中定义,以便优雅地处理半透明工具栏等) .
首先,定义一个小帮手:
要保留原始插图,请定义字段:
在viewDidLoad中的某个地方填写它:
将UIImageView放入UIScrollView(假设UIImage本身位于loadedImage var中):
scrollViewDidZoom:来自UIScrollViewDelegate的滚动视图:
最后,以自身为中心:
我还没有测试方向改变(即调整UIScrollView本身的适当反应),但修复它应该相对容易 .
您会发现Erdemus发布的解决方案确实有效,但是......在某些情况下,不会调用scrollViewDidZoom方法并且您的图像卡在左上角 . 一个简单的解决方案是在最初显示图像时显式调用该方法,如下所示:
在许多情况下,您可能会两次调用此方法,但这是一个比本主题中的其他一些答案更清晰的解决方案 .
Apple的Photo Scroller示例完全符合您的要求 . 将它放在您的UIScrollView子类中,并将_zoomView更改为您的UIImageView .
Apple's Photo Scroller Sample Code
我这样做的方法是在层次结构中添加一个额外的视图:
为
UIView
提供与UIScrollView
相同的宽高比,并将UIImageView
置于其中心 .为了使动画流畅,请设置
并使用此功能(使用this answer中的方法查找中心)
这会产生弹跳效果,但不会事先涉及任何突然的动作 .
只是swift中的已批准答案,但没有使用委托进行子类化
如果您的内部imageView具有初始特定宽度(例如300),并且您只想将其宽度 only 放在缩小比其初始宽度小的位置,这也可能对您有所帮助 .
这是我正在做这项工作的当前方式 . 它更好但仍然不完美 . 尝试设置:
修复
minZoomScale
时视图不居中的问题 .此外,我执行以下操作以防止图像在缩小后粘在一侧 .
好的,我想我找到了一个很好的解决方案 . 诀窍是不断重新调整
imageView's
帧 . 我发现这比不断调整contentInsets
或contentOffSets
要好得多 . 我不得不添加一些额外的代码来容纳纵向和横向图像 .这是代码:
只是禁用分页,所以它会工作正常:
我有同样的问题 . 这是我如何解决的
应该将此代码作为
scrollView:DidScroll:
的结果调用虽然这个问题有点陈旧但问题仍然存在 . 我在 Xcode 7 中通过将最上面的项目(在本例中为
topLabel
)的垂直空间约束设置为superViews(scrollView
)顶部IBOutlet
然后每次内容根据scrollView的子视图的高度更改时重新计算其常量来解决它(topLabel
和bottomLabel
) .