应用CGAffineTransform后获取UIView的大小

21

我很惊讶地发现没有针对这个问题的答案,也许是我忽略了一些非常简单的东西:

如何在应用CGAffineTransform之后获取UIView的实际大小?

例如:

我的UIView大小为300 x 200,我应用了一个缩放变换,水平和垂直因子均为2,因此UIView现在在屏幕上占据600 x 400的空间,但它的边界和图层的边界仍然返回300 x 200的大小...那么我在哪里可以找到UIView的真实大小?

附:我忘了提到我还想旋转uiview。如果只应用缩放,则CGSizeApplyAffineTransform效果很好,但如果还有旋转,则不起作用。

编辑:drawnonward指导了我正确的方向,我只是稍微修改了一下代码,现在放在这里:

UIView* view = (your view being transformed);
CGAffineTransform trans = (view.transform or create a new transformation);

CGRect rect = [view bounds];
CGMutablePathRef path = CGPathCreateMutable();
rect.origin = CGPointZero;
CGPathAddRect(path , &trans , rect);
rect = CGPathGetBoundingBox( path );
CGPathRelease( path );

现在,rect.size 包含了应用变换后视图的尺寸。再次感谢 drawnonward。

7个回答

47

我在 Objective C 中使用了这段代码:

CGRect transformedBounds = CGRectApplyAffineTransform(view.bounds, view.transform);

或者在 Swift 4 中:

let transformedBounds = view.bounds.applying(view.transform)

我认为只使用“view.bounds”会是一个更好的答案。为什么你在这里转换边界而不是直接获取框架的大小呢? - Andrew Paul Simmons

12
[myView frame]返回视图相对于父视图的位置和大小, 用于布局和相对尺寸. [myView bounds]返回视图本身的位置和大小, 用于绘制. 如果你对多个视图应用了变换, 可以使用convertRect:在不同视图之间进行转换。
CGRect rect = [view bounds];
CGPathRef path = CGPathCreateMutable();
rect.origin = CGPointZero;
CGPathAddRect( rect , [view transform] );
rect = CGPathGetBoundingBox( path );
CGPathRelease( path );

使用[view center]来找到父视图中的位置。


1
这是苹果文档关于“frame”的说明: 警告:如果变换属性不是单位矩阵,则此属性的值未定义,因此应将其忽略。因此,在应用变换时,框架是不可用的。 而“bounds”始终返回原始大小。 - Marin Todorov
确实!啊,这些函数库我总是忘记 - CGPathGetBoundingBox就是诀窍。我用可工作的代码编辑了问题,非常感谢你。 - Marin Todorov
请注意,即使使用非标识变换,center属性也应该正常工作。 - Olie

4

虽然这是一个老问题,但我在搜索解决方案并尝试了很多次后才找到这里。问题其实很简单;

view.layer.frame 已经应用了所有的变换,你可以轻松地从 view.layer.frame.size 中获取大小。

-- 以下不是对此问题的回答 --

对于我的问题,我试图计算旋转视图更改 layer.anchorPoint 后的新 center 值,以便它不会移动。最终我是这样做的;

CGPoint topLeft = [self.superview convertPoint:CGPointMake(0, 0) fromView:self];
self.layer.anchorPoint = CGPointMake(0, 0);
self.center = topLeft;

用于反转

CGPoint center = [self.superview convertPoint:CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2) fromView:self];
self.layer.anchorPoint = CGPointMake(.5, .5);
self.center = center;

最终完成。

3
使用 CGSizeApplyAffineTransform(size, transform) 函数,可以返回一个经过变换后的尺寸。还有类似的 CGPointCGRect 函数。

如果CGSizeApplyAffineTransform包含旋转,则无法正常工作,但是在仅应用缩放的情况下,您是正确的。(我的错误是我没有在问题中包括旋转) - Marin Todorov

2
更简单的表述:对一个大小为s的视图应用变换tr后,其结果大小为:
CGSizeMake(s.width*hypotf(tr.a, tr.b), s.height*hypotf(tr.c, tr.d))

然而,如果视图的 superview 或任何祖先视图有任何非单位转换应用,则此大小在绝对意义上没有太大意义。

如果您想要在将任意变换应用于该视图或其 superviews 后以窗口坐标计算视图的绝对大小,则应首先通过组合直到根窗口所有视图变换来计算绝对变换矩阵,然后将上述公式应用于结果。


0

但是如果您应用旋转变换,它将无法通过CGPathGetBoundingBox获得正确的大小。


0
如果您应用了CGAffineTransform到视图的.layer,那么在缩放和/或平移变换后调整的CGRect区域就是view.layer.frame

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接