我需要在原始视图的坐标中计算UIView子视图的可见CGRect。如果缩放比例为1,则可以正常工作,但是如果对某个超级视图或视图本身进行缩放(捏),则可见CGRect原点会稍微偏移。
当视图的比例为1或该视图是根视图的子视图时,此方法有效:
// return the part of the passed view that is visible
// TODO: figure out why result origin is wrong for scaled subviews
//
- (CGRect)getVisibleRect:(UIView *)view {
// get the root view controller (and it's view is vc.view)
UIViewController *vc = UIApplication.sharedApplication.keyWindow.rootViewController;
// get the view's frame in the root view's coordinate system
CGRect frame = [vc.view convertRect:view.frame fromView:view.superview];
// get the intersection of the root view bounds and the passed view frame
CGRect intersection = CGRectIntersection(vc.view.bounds, frame);
// adjust the intersection coordinates thru any nested views
UIView *loopView = view;
do {
intersection = [loopView convertRect:intersection fromView:loopView.superview];
loopView = loopView.superview;
} while (loopView != vc.view);
return intersection; // may be same as the original view frame
}
缩放子视图时,结果视图的大小是正确的,但原点会偏移少量。看来convertRect
不能正确计算缩放后的子视图的原点。
我尝试相对于X / Y变换比例调整原点,但无法正确计算。也许有人可以帮忙?
为节省时间,这是一个完整的ViewController.m测试,其中在视图的可见部分上绘制了一个带有X的框-只需在Main.storyboard中创建一个reset按钮并将其连接到{{1 }}方法:
reset
答案 0 :(得分:2)
因此,您需要知道以某种方式从frame
+ bounds
+ center
派生而来的视图的真实可见transform
,并从中计算其他所有内容,而不是普通的frame
值。这意味着您还必须重新创建convertRect:fromView:
以基于此。我总是通过仅对不需要这种计算的短动画使用transform
来避免这个问题。考虑编码这样的-getVisibleRect:
方法使我想逃避尖叫;)
frame
? frame
属性是从center
和bounds
派生的。
示例:
center
是(60,50)
bounds
是(0,0,100,100)
frame
是(10,0,100,100)
现在,您将frame
更改为(10,20,100,100)
。因为视图的大小没有改变,所以只会导致center
的改变。新的center
现在为(60,70)
。
transform
怎么样?假设您现在将视图缩放到50%来对其进行变换。
=>现在,视图的大小是以前的一半,而中心仍然保持不变。看起来新框架是(35,45,50,50)
。但是实际结果是:
center
仍然是(60,50)
:这是预期的bounds
仍然是(0,0,100,100)
:这应该也是预期的frame
仍然是(10,20,100,100)
:这有点违反直觉 frame
是一个计算所得的属性,它与当前的transform
完全无关。这意味着只要frame
不是身份变换,transform
的值就没有意义。这甚至是documented behaviour。 Apple在这种情况下将frame
的值称为“未定义”。
这会带来额外的后果,当涉及到非标准转换时,诸如convertRect:fromView:
之类的方法将无法正常工作。这是因为所有这些方法都依赖于视图的frame
或bounds
,并且一旦涉及到转换,它们就会立即中断。
假设您有三种视图:
您想从view1的角度知道view3的坐标。
从view2的角度来看,view3具有框架view3.frame
。简单。
从view1的角度来看,view2没有框架view2.frame
,但是可见的框架是矩形,大小为view2.bounds/2
,中心为view2.center
。
要正确处理此问题,您需要一些基本的线性代数(带有矩阵乘法)。 (并且不要忘记anchorPoint ..)
希望对您有帮助。
在您的问题中,您说有一个偏移量。也许您现在可以计算误差?该错误应类似于0.5 *(1-scale)*(bounds.size)。如果可以计算出误差,则可以将其减去并称之为一天:)
答案 1 :(得分:0)
感谢@Michael付出了很多努力。它没有解决问题,但使我思考了更多,然后尝试了其他一些事情。
瞧,我尝试了以前可以做的事情,但是这次我以最新的代码开始。事实证明,有一个简单的解决方案可以解决问题。内置UIView
convertRect:fromView
和convertRect:toView
一起使用时可以按预期工作。
我向在此问题上花费时间的任何人表示歉意。我对自己的愚蠢以及在其中花费了多少时间感到谦卑。我以前尝试过此操作时一定在某个地方犯了一个错误,因为它不起作用。但这现在效果很好:
// return the part of the passed view that is visible
- (CGRect)getVisibleRect:(UIView *)view {
// get the root view controller (and it's view is vc.view)
UIViewController *vc = UIApplication.sharedApplication.keyWindow.rootViewController;
// get the view's frame in the root view's coordinate system
CGRect rootRect = [vc.view convertRect:view.frame fromView:view.superview];
// get the intersection of the root view bounds and the passed view frame
CGRect rootVisible = CGRectIntersection(vc.view.bounds, rootRect);
// convert the rect back to the initial view's coordinate system
CGRect visible = [view convertRect:rootVisible fromView:vc.view];
return visible; // may be same as the original view frame
}
如果有人使用我问题中的Viewcontroller.m
,只需用此方法替换getVisibleRect方法,它将很好地工作。
注意:我尝试旋转视图,并且可见矩形也被旋转,因为我将其显示在视图本身上。我想我可以反转形状图层上的任何视图旋转,但这是另一天!