获取 UIScrollView 内容的可见校正

我怎样才能找出在屏幕上实际可见的显示视图的正确内容(CGRect)。

myScrollView.bounds

上面的代码在没有缩放的情况下可以工作,但是一旦允许缩放,它就会在1以外的缩放比例上出现故障。

为了澄清,我需要一个 CGRect,它包含滚动视图内容相对于内容的可见区域。(即。如果是缩放比例为2,则最近的尺寸将是滚动视图尺寸的一半,如果是缩放比例为0.5,则为两倍。)

73399 次浏览

我不认为 UIScrollView 可以直接给出那个矩形,但是我认为您拥有计算矩形所需的所有条目。

边界、 contentOffset 和 zoomScale 的组合应该是创建所需矩形的全部内容。

您必须使用 UIScrollView 的 contentOffset 和 contentSize 属性来计算它,如下所示:

CGRect visibleRect;
visibleRect.origin = scrollView.contentOffset;
visibleRect.size = scrollView.contentSize;

然后您可以将其记录下来进行健全性测试:

NSLog( @"Visible rect: %@", NSStringFromCGRect(visibleRect) );

为了解决缩放问题(如果 contentSize 属性还没有做到这一点) ,你需要用 zoomScale 除以每个坐标,或者为了获得更好的性能,你需要乘以1.0/zoomScale:

CGFloat scale = (CGFloat) 1.0 / scrollView.zoomScale;
if ( isless(scale, 1.0) )      // you need to #include <math.h> for isless()
{
visibleRect.origin.x *= scale;
visibleRect.origin.y *= scale;
visibleRect.size.width *= scale;
visibleRect.size.height *= scale;
}

旁白: 我在 math.h 中使用了 isless () ,isbetter () ,isequal ()等,因为(大概)这些对于“无序的”浮点比较结果和其他奇怪而精彩的特定于架构的 FP 案例来说是正确的。


编辑: 在计算 visibleRect.size时,需要使用 bounds.size而不是 contentSize

回答我自己的问题,主要是因为吉姆•多维(Jim Dovey)的回答。虽然这个回答没有起到什么作用,但却为我的回答提供了基础:

CGRect visibleRect;
visibleRect.origin = scrollView.contentOffset;
visibleRect.size = scrollView.bounds.size;


float theScale = 1.0 / scale;
visibleRect.origin.x *= theScale;
visibleRect.origin.y *= theScale;
visibleRect.size.width *= theScale;
visibleRect.size.height *= theScale;

主要的区别在于 visableRect 的大小应该是 scrollView.bounds.size,而不是 scrollView.contentSize,后者是内容视图的大小。也简化了数学一点,并没有完全看到使用 isless(),这将破坏代码每当它更大。

CGRect visibleRect;
visibleRect.origin = scrollView.contentOffset;
visibleRect.size = scrollView.frame.size;

或者你可以直接

CGRect visibleRect = [scrollView convertRect:scrollView.bounds toView:zoomedSubview];

斯威夫特

let visibleRect = scrollView.convert(scrollView.bounds, to: zoomedSubview)

简短版:

CGRect visibleRect = CGRectApplyAffineTransform(scrollView.bounds, CGAffineTransformMakeScale(1.0 / scrollView.zoomScale, 1.0 / scrollView.zoomScale));

我不确定这是否是已定义的行为,但几乎所有 UIView 子类的 bounds原点都设置为(0,0)。但是,UIScrollView 的原点设置为 contentOffset

一个更普遍的解决办法是:

 [scrollView convertRect:scrollView.bounds
toView:[scrollView.delegate viewForZoomingInScrollView:scrollView]];

Swift 4.0:

我的回答将 Trenskow 的回答改编成了 Swift 4.0:

let visible = scrollView.convert(scrollView.bounds, to: subView)

其中 scrollView是卷轴的视图,而 subViewscrollView内部的视图,它是可缩放的,包含卷轴内部的所有内容。