我正在使用最新的SDK开发iOS应用。

我这样创建一个AVCaptureVideoPreviewLayer

// Create the preview layer
_videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
[_videoPreviewLayer setFrame:self.view.bounds];
_videoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.view.layer insertSublayer:_videoPreviewLayer atIndex:0];


现在我要这样做:

_videoPreviewLayer.affineTransform = CGAffineTransformMakeScale(2, 2);


但是,如果将其放在[_videoPreviewLayer setFrame:self.view.bounds];之前,则得到的结果与之后的结果不同。

我必须在哪里应用规模?

而且,如果要设置CGAffineTransformMakeRotation(-M_PI_2); // -90 degrees,该在哪里做?

最佳答案

您不应在其转换不是标识的视图上使用setFrame。根据Apple关于UIView的frame属性的文档:


  如果transform属性不是恒等变换,则此属性[frame]的值未定义,因此应忽略。


在UIView.h中,在frame属性上方


  如果视图已转换,请不要使用框架,因为它不能正确反映视图的实际位置。请改用bounds + center。


因此,如果在此代码中切换到使用setBounds和setCenter而不是setFrame,则可能会得到所需的一致结果。

要直接回答这个问题:如果还使用setFrame,则没有正确的位置放置这些变换(比例或旋转)。如果使用setBounds和setCenter,则无论在setBounds / setCenter之前还是setBounds / setCenter之后应用转换,都将获得相同的结果。

编辑:VansFannel指出这是一个CALayer,而不是UIView,因此上面的注释并不适用。我离开他们是为了不剥夺VansFannel对上下文的评论,也因为它仍然是UIViews的一个很好的警告。

现在,对于CALayers,如果您设置帧(例如[_videoPreviewLayer setFrame:self.view.bounds]),即使_videoPreviewLayer进行了非身份转换,也会导致_videoPreviewLayer的实际渲染帧为self.view.bounds。重要的是要记住,CALayer的框架实际上是派生的属性。它是从图层的边界,位置,anchorPoint和transform派生的。当使用setFrame时,QuartzCore将找出边界和位置,以产生在现有的anchorPoint和transform下传递给setFrame的帧。

因此,如果您希望这些转换具有任何效果,则应在调用setFrame之后将其放置。如果先设置转换,则setFrame将有效地将其取反。如果绝对需要首先设置转换,则必须避免使用setFrame并直接使用图层的边界和位置。

08-18 12:54