在我的iPhone应用程序,我需要为用户提供放大/屏幕上平移一个大十岁上下的图像的能力。 这是很简单:我用UIScrollView
,设置最大/最小的比例因子和缩放/平移按预期工作。 这就是事情变得有趣。 的图像是动态的,从服务器接收。 它可以有任意尺寸。 当图像第一负载,它的按比例缩小(如果需要)以完全装配到UIScrollView
和在滚动视图的中心-截图低于:
因为该图像的比例是那些滚动视图的不同,有以上,并且使得图像居中图像下方添加空白区域。 然而,当我开始缩放图像,实际图像大到足以填满整个滚动视图视口,因此在顶部/底部垫衬白色不再需要的,但是他们仍然存在,从这个截图中可以看出:
我相信这是由于事实UIImageView
包含图像自动调整大小以填满整个UIScrollView
和放大时,它只是按比例增长。 它具有缩放模式设置为Aspect Fit
。 UIScrollView
的委托viewForZoomingInScrollView
简单地返回图像视图。
我试图重新计算和重新设置UIScrollView
, contentSize
和图像视图的大小scrollViewDidEndZooming
方法:
CGSize imgViewSize = imageView.frame.size;
CGSize imageSize = imageView.image.size;
CGSize realImgSize;
if(imageSize.width / imageSize.height > imgViewSize.width / imgViewSize.height) {
realImgSize = CGSizeMake(imgViewSize.width, imgViewSize.width / imageSize.width * imageSize.height);
}
else {
realImgSize = CGSizeMake(imgViewSize.height / imageSize.height * imageSize.width, imgViewSize.height);
}
scrollView.contentSize = realImgSize;
CGRect fr = CGRectMake(0, 0, 0, 0);
fr.size = realImgSize;
imageView.frame = fr;
然而,这只是使事情变得更糟(有界仍然存在,但平移在垂直方向上不工作)。
有没有什么办法,因为它成为不必要的自动减少空白,然后放大期间再次增加? 我怀疑工作将需要做scrollViewDidEndZooming
,但我也不太清楚这是什么代码需要。
Answer 1:
真棒!
感谢您的代码:)
只是想我会添加到这个,我改变了它稍微改善行为。
// make the change during scrollViewDidScroll instead of didEndScrolling...
-(void)scrollViewDidZoom:(UIScrollView *)scrollView
{
CGSize imgViewSize = self.imageView.frame.size;
CGSize imageSize = self.imageView.image.size;
CGSize realImgSize;
if(imageSize.width / imageSize.height > imgViewSize.width / imgViewSize.height) {
realImgSize = CGSizeMake(imgViewSize.width, imgViewSize.width / imageSize.width * imageSize.height);
}
else {
realImgSize = CGSizeMake(imgViewSize.height / imageSize.height * imageSize.width, imgViewSize.height);
}
CGRect fr = CGRectMake(0, 0, 0, 0);
fr.size = realImgSize;
self.imageView.frame = fr;
CGSize scrSize = scrollView.frame.size;
float offx = (scrSize.width > realImgSize.width ? (scrSize.width - realImgSize.width) / 2 : 0);
float offy = (scrSize.height > realImgSize.height ? (scrSize.height - realImgSize.height) / 2 : 0);
// don't animate the change.
scrollView.contentInset = UIEdgeInsetsMake(offy, offx, offy, offx);
}
Answer 2:
这里是我的解决方案,可与任何标签栏或导航栏组合或W / O两种工作普遍,半透明或不。
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
// The scroll view has zoomed, so you need to re-center the contents
CGSize scrollViewSize = [self scrollViewVisibleSize];
// First assume that image center coincides with the contents box center.
// This is correct when the image is bigger than scrollView due to zoom
CGPoint imageCenter = CGPointMake(self.scrollView.contentSize.width/2.0,
self.scrollView.contentSize.height/2.0);
CGPoint scrollViewCenter = [self scrollViewCenter];
//if image is smaller than the scrollView visible size - fix the image center accordingly
if (self.scrollView.contentSize.width < scrollViewSize.width) {
imageCenter.x = scrollViewCenter.x;
}
if (self.scrollView.contentSize.height < scrollViewSize.height) {
imageCenter.y = scrollViewCenter.y;
}
self.imageView.center = imageCenter;
}
//return the scroll view center
- (CGPoint)scrollViewCenter {
CGSize scrollViewSize = [self scrollViewVisibleSize];
return CGPointMake(scrollViewSize.width/2.0, scrollViewSize.height/2.0);
}
// Return scrollview size without the area overlapping with tab and nav bar.
- (CGSize) scrollViewVisibleSize {
UIEdgeInsets contentInset = self.scrollView.contentInset;
CGSize scrollViewSize = CGRectStandardize(self.scrollView.bounds).size;
CGFloat width = scrollViewSize.width - contentInset.left - contentInset.right;
CGFloat height = scrollViewSize.height - contentInset.top - contentInset.bottom;
return CGSizeMake(width, height);
}
为什么它比其他任何我能找到这么这么远好:
它不读取或修改图像视图的UIView的帧的性能,因为缩放图像视图具有变换应用到它。 见这里什么苹果说如何移动或当施加非恒等变换调整视图大小。
其中半透明酒吧被引入该系统启动的iOS 7会自动调整滚动视图大小,滚动内容的插图和滚动指标偏移。 因此,你不应该在你的代码修改这些为好。
FYI:用于切换这种行为在Xcode界面生成器(这是默认设置)有很复选框。 您可以在视图控制器属性找到它:
完整视图控制器的源代码被发布在这里 。
您也可以下载整个Xcode项目看到滚动视图约束,建立并通过移动最初的控制器指针到下列路径玩弄情节板中的3个不同的预设:
- 查看与两个半透明的标签和导航条。
- 查看与两个不透明的标签和导航条。
- 查看没有条可言。
每个选项都具有相同的VC实现正常工作。
Answer 3:
我想我得到了它。 该解决方案是使用scrollViewDidEndZooming
委托的方法和在该方法中设置contentInset
基于所述图像的尺寸。 下面就是该方法的样子:
- (void)scrollViewDidEndZooming:(UIScrollView *)aScrollView withView:(UIView *)view atScale:(float)scale {
CGSize imgViewSize = imageView.frame.size;
CGSize imageSize = imageView.image.size;
CGSize realImgSize;
if(imageSize.width / imageSize.height > imgViewSize.width / imgViewSize.height) {
realImgSize = CGSizeMake(imgViewSize.width, imgViewSize.width / imageSize.width * imageSize.height);
}
else {
realImgSize = CGSizeMake(imgViewSize.height / imageSize.height * imageSize.width, imgViewSize.height);
}
CGRect fr = CGRectMake(0, 0, 0, 0);
fr.size = realImgSize;
imageView.frame = fr;
CGSize scrSize = scrollView.frame.size;
float offx = (scrSize.width > realImgSize.width ? (scrSize.width - realImgSize.width) / 2 : 0);
float offy = (scrSize.height > realImgSize.height ? (scrSize.height - realImgSize.height) / 2 : 0);
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.25];
scrollView.contentInset = UIEdgeInsetsMake(offy, offx, offy, offx);
[UIView commitAnimations];
}
请注意,我使用上设置的插图动画,否则图像滚动视图内进行跳转,添加插图时。 随着动画它的幻灯片的中心。 我使用UIView
beginAnimation
和commitAnimation
而不是动画块的,因为我需要对iPhone 3的应用程序运行。
Answer 4:
这里是SWIFT 3版本的亨克的 答案
func scrollViewDidZoom(_ scrollView: UIScrollView){
let imgViewSize:CGSize! = self.imageView.frame.size;
let imageSize:CGSize! = self.imageView.image?.size;
var realImgSize : CGSize;
if(imageSize.width / imageSize.height > imgViewSize.width / imgViewSize.height) {
realImgSize = CGSize(width: imgViewSize.width,height: imgViewSize.width / imageSize.width * imageSize.height);
}
else {
realImgSize = CGSize(width: imgViewSize.height / imageSize.height * imageSize.width, height: imgViewSize.height);
}
var fr:CGRect = CGRect.zero
fr.size = realImgSize;
self.imageView.frame = fr;
let scrSize:CGSize = scrollView.frame.size;
let offx:CGFloat = (scrSize.width > realImgSize.width ? (scrSize.width - realImgSize.width) / 2 : 0);
let offy:CGFloat = (scrSize.height > realImgSize.height ? (scrSize.height - realImgSize.height) / 2 : 0);
scrollView.contentInset = UIEdgeInsetsMake(offy, offx, offy, offx);
// The scroll view has zoomed, so you need to re-center the contents
let scrollViewSize:CGSize = self.scrollViewVisibleSize();
// First assume that image center coincides with the contents box center.
// This is correct when the image is bigger than scrollView due to zoom
var imageCenter:CGPoint = CGPoint(x: self.scrollView.contentSize.width/2.0, y:
self.scrollView.contentSize.height/2.0);
let scrollViewCenter:CGPoint = self.scrollViewCenter()
//if image is smaller than the scrollView visible size - fix the image center accordingly
if (self.scrollView.contentSize.width < scrollViewSize.width) {
imageCenter.x = scrollViewCenter.x;
}
if (self.scrollView.contentSize.height < scrollViewSize.height) {
imageCenter.y = scrollViewCenter.y;
}
self.imageView.center = imageCenter;
}
//return the scroll view center
func scrollViewCenter() -> CGPoint {
let scrollViewSize:CGSize = self.scrollViewVisibleSize()
return CGPoint(x: scrollViewSize.width/2.0, y: scrollViewSize.height/2.0);
}
// Return scrollview size without the area overlapping with tab and nav bar.
func scrollViewVisibleSize() -> CGSize{
let contentInset:UIEdgeInsets = self.scrollView.contentInset;
let scrollViewSize:CGSize = self.scrollView.bounds.standardized.size;
let width:CGFloat = scrollViewSize.width - contentInset.left - contentInset.right;
let height:CGFloat = scrollViewSize.height - contentInset.top - contentInset.bottom;
return CGSize(width:width, height:height);
}
Answer 5:
这里是关于夫特3.1测试的延伸。 只要创建一个单独的* .swift文件并粘贴下面的代码:
import UIKit
extension UIScrollView {
func applyZoomToImageView() {
guard let imageView = delegate?.viewForZooming?(in: self) as? UIImageView else { return }
guard let image = imageView.image else { return }
guard imageView.frame.size.valid && image.size.valid else { return }
let size = image.size ~> imageView.frame.size
imageView.frame.size = size
self.contentInset = UIEdgeInsets(
x: self.frame.size.width ~> size.width,
y: self.frame.size.height ~> size.height
)
imageView.center = self.contentCenter
if self.contentSize.width < self.visibleSize.width {
imageView.center.x = self.visibleSize.center.x
}
if self.contentSize.height < self.visibleSize.height {
imageView.center.y = self.visibleSize.center.y
}
}
private var contentCenter: CGPoint {
return CGPoint(x: contentSize.width / 2, y: contentSize.height / 2)
}
private var visibleSize: CGSize {
let size: CGSize = bounds.standardized.size
return CGSize(
width: size.width - contentInset.left - contentInset.right,
height: size.height - contentInset.top - contentInset.bottom
)
}
}
fileprivate extension CGFloat {
static func ~>(lhs: CGFloat, rhs: CGFloat) -> CGFloat {
return lhs > rhs ? (lhs - rhs) / 2 : 0.0
}
}
fileprivate extension UIEdgeInsets {
init(x: CGFloat, y: CGFloat) {
self.bottom = y
self.left = x
self.right = x
self.top = y
}
}
fileprivate extension CGSize {
var valid: Bool {
return width > 0 && height > 0
}
var center: CGPoint {
return CGPoint(x: width / 2, y: height / 2)
}
static func ~>(lhs: CGSize, rhs: CGSize) -> CGSize {
switch lhs > rhs {
case true:
return CGSize(width: rhs.width, height: rhs.width / lhs.width * lhs.height)
default:
return CGSize(width: rhs.height / lhs.height * lhs.width, height: rhs.height)
}
}
static func >(lhs: CGSize, rhs: CGSize) -> Bool {
return lhs.width / lhs.height > rhs.width / rhs.height
}
}
使用方式:
extension YOUR_SCROLL_VIEW_DELEGATE: UIScrollViewDelegate {
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return YOUR_IMAGE_VIEW
}
func scrollViewDidZoom(_ scrollView: UIScrollView){
scrollView.applyZoomToImageView()
}
}
文章来源: Keep zoomable image in center of UIScrollView