6

在此处输入图像描述 摘要: 我无法强制 CALayer 正确响应方向变化。每当我尝试使用 cgaffinetransform 时,我都会得到奇怪的结果(图层未居中)。任何帮助将不胜感激!谢谢,

过程 我正在使用 AVCaptureVideoPreviewLayer 子类添加视频预览。当设备处于纵向时,一切看起来都很好。当设备旋转到横向(左或右)或纵向倒置时会出现问题。

我正在使用 AVCaptureVideoPreviewLayer 子类添加视频预览。当设备处于纵向时,一切看起来都很好。当设备旋转到横向(左或右)或纵向倒置时会出现问题。

我正在使用以下代码添加预览层:

CGRect layerRect = [[[self view] layer] bounds];
[[[self captureManager] previewLayer] setBounds:layerRect];
[[[self captureManager] previewLayer]setFrame:CGRectMake(0, height, width, height)];
[[[self captureManager] previewLayer] setPosition:CGPointMake(CGRectGetMidX(layerRect),CGRectGetMidY(layerRect))];

并且在纵向模式下正确显示。当我尝试旋转设备时,预览层的行为很奇怪。它似乎没有自行调整大小,也没有正确旋转。

我尝试通过添加以下方法来修复它

-(void)rotateLayer{
CALayer * stuckview = [[self captureManager] previewLayer];
CGRect layerRect = [[[self view] layer] bounds];

UIDeviceOrientation orientation =[[UIDevice currentDevice]orientation];

switch (orientation) {
    case UIDeviceOrientationLandscapeLeft:
        stuckview.affineTransform = CGAffineTransformMakeRotation(M_PI+ M_PI_2); // 270 degress
        NSLog(@"Landscape Left");
        [stuckview setPosition: CGPointMake(self.view.bounds.size.width /2.0, self.view.bounds.size.height /2.0)];

        break;
    case UIDeviceOrientationLandscapeRight:
        stuckview.affineTransform = CGAffineTransformMakeRotation(M_PI_2); // 90 degrees
        NSLog(@"Landscape Right");
        [stuckview setPosition: CGPointMake(self.view.bounds.size.width /2.0, self.view.bounds.size.height /2.0)];
        break;
    case UIDeviceOrientationPortraitUpsideDown:
        stuckview.affineTransform = CGAffineTransformMakeRotation(M_PI); // 180 degrees
        NSLog(@"Landscape Upside down");
        break;
    default:
        stuckview.affineTransform = CGAffineTransformMakeRotation(0.0);
        break;
}
 float h1 = stuckview.frame.size.height;
   float w1 = stuckview.frame.size.width;

if(UIDeviceOrientationIsPortrait(orientation))
{
  stuckview.position =CGPointMake(h1/2.0, w1/2.0);
    NSLog(@"Portrait");
}
else{
  stuckview.position =CGPointMake(w1/2.0, h1/2.0);
    NSLog(@"Portrait");
}

}

添加上面的方法后,我可以看到一个进度。现在图层可以正确旋转以反映当前设备方向,并且可以在横向模式下正确显示,但不能在纵向模式下显示。

图层定位不正确,不在屏幕中心(看截图)。要查看发生了什么,我添加了以下调试语句:

CALayer * stuckview = [[self captureManager] previewLayer];
CGRect layerRect = [[[self view] layer] bounds];
float h = stuckview.bounds.size.height;
float w = stuckview.bounds.size.width;

float x = stuckview.bounds.origin.x;
float y = stuckview.bounds.origin.y;

float h1 = stuckview.frame.size.height;
float w1 = stuckview.frame.size.width;

float x1 = stuckview.frame.origin.x;
float y1 = stuckview.frame.origin.y;

NSLog(@"%f %f %f %f ", h,w,x,y );
NSLog(@"%f %f %f %f ", h1,w1,x1,y1 );

NSLog(@"Anchor Point: %f  %f",stuckview.anchorPoint.x, stuckview.anchorPoint.y);
NSLog(@"Position: %f  %f",stuckview.position.x, stuckview.position.y);

CGAffineTransform at = stuckview.affineTransform;

NSLog(@"Affine Transform After : %f %f %f %f %f %f %f", at.a,at.b, at.c, at.d, at.tx,at.tx, at.ty);

并得到以下输出:

2012-09-30 13:25:12.067 RotatePreviewLayer[2776:907] 1024.000000 768.000000 0.000000 0.000000 

2012-09-30 RotatePreviewLayer[2776:907] 1024.000000 768.000000 128.000000 -128.000000

2012-09-30 13:25:12.070 RotatePreviewLayer[2776:907] Portrait
2012-09-30 13:25:12.072 RotatePreviewLayer[2776:907] Anchor Point: 0.500000  0.500000
2012-09-30 13:25:12.074 RotatePreviewLayer[2776:907] Position: 512.000000  384.000000
2012-09-30 13:25:12.076 RotatePreviewLayer[2776:907] Affine Transform after: -1.000000 0.000000 -0.000000 -1.000000 0.000000 0.000000 0.000000

注意调试输出的第二行。预览层的框架移动了128,-128。谁能解释一下为什么会发生这种情况以及如何解决预览层的方向问题?谢谢你,亚努斯

4

8 回答 8

9

那这个呢?

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    _videoPreviewLayer.connection.videoOrientation = toInterfaceOrientation;
}
于 2013-10-22T05:26:43.990 回答
6

这是我在视图控制器中使用的方法来保持捕获层的方向,使其始终是正面朝上的:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
    if (_previewLayer.connection.supportsVideoOrientation)
    {
    switch (toInterfaceOrientation)
        {
        case UIInterfaceOrientationPortrait:
            {
            _previewLayer.connection.videoOrientation = AVCaptureVideoOrientationPortrait;
            break;
            }
        case UIInterfaceOrientationPortraitUpsideDown:
            {
            _previewLayer.connection.videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown;
            break;
            }
        case UIInterfaceOrientationLandscapeLeft:
            {
            _previewLayer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeLeft;
            break;
            }
        case UIInterfaceOrientationLandscapeRight:
            {
            _previewLayer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
            break;
            }
        }
    }

有点罗嗦,但即使任何一个枚举在未来发生变化也是安全的。

于 2013-09-03T20:22:46.000 回答
5

我仍然不确定是什么导致了问题,但我设法解决了它。这是我的做法:

在 viewDidLoad 我添加了一个图层:

CGRect layerRect = [[[self view] layer] bounds];
    [[[self captureManager] previewLayer] setBounds:layerRect];
    [[[self captureManager] previewLayer] setPosition:CGPointMake(CGRectGetMidX(layerRect),CGRectGetMidY(layerRect))];
    [[[self view] layer] addSublayer:[[self captureManager] previewLayer]];

然后我将调用 rotateLayer 方法添加到 didRotate

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
    [self rotateLayer];
}

最后 rotateLayer 方法如下所示:

-(void)rotateLayer{
    CALayer * stuckview = [[self captureManager] previewLayer];
    CGRect layerRect = [[[self view] layer] bounds];

    UIDeviceOrientation orientation =[[UIDevice currentDevice]orientation];

    switch (orientation) {
        case UIDeviceOrientationLandscapeLeft:
            stuckview.affineTransform = CGAffineTransformMakeRotation(M_PI+ M_PI_2); // 270 degress

            break;
        case UIDeviceOrientationLandscapeRight:
            stuckview.affineTransform = CGAffineTransformMakeRotation(M_PI_2); // 90 degrees
            break;
        case UIDeviceOrientationPortraitUpsideDown:
            stuckview.affineTransform = CGAffineTransformMakeRotation(M_PI); // 180 degrees
            break;
        default:
            stuckview.affineTransform = CGAffineTransformMakeRotation(0.0);
            [stuckview setBounds:layerRect];
            break;
    }
    [stuckview setPosition:CGPointMake(CGRectGetMidX(layerRect),CGRectGetMidY(layerRect))];
}

我仍然不明白为什么它会以这种方式工作。如果有人可以解释,那就太好了。

于 2012-10-02T15:30:10.277 回答
1

@Janusz Chudzynski 这里是详细解释什么rotateLayer方法

此方法是在检查不同方向如何影响之后previewLayer创建LandscapeLeft

stuckview.affineTransform = CGAffineTransformMakeRotation(M_PI+ M_PI_2);

     M_PI        3.14159265358979323846264338327950288   // pi     = 180 degree  
                                    +      
     M_PI_2      1.57079632679489661923132169163975144   // pi/2   = 90  degree

                                                         // Total  = 270 degree

所以创造者已经注意到,如果我previewLayer在它进入时旋转到 270 度,LandscapeLeft那么它将处于正确的位置,就像他在previewLayer每一次可能的旋转中都旋转一样

于 2013-08-09T06:53:27.493 回答
0
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration  
{  
    previewLayer.orientation = toInterfaceOrientation;  
}
于 2012-10-04T11:13:28.850 回答
0

我和@Siegfault 在一起,虽然我也发现当我的视图最初在iPad 上以横向加载时,方向仍然正确。viewDidAppear:为了解决这个问题,我使用当前调用相同的委托方法interfaceOrientation

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self willRotateToInterfaceOrientation:self.interfaceOrientation duration:0.0];
}
于 2015-04-06T19:07:23.620 回答
0

使用 willRotateToUserInterfaceOrientation 的答案工作正常,除了该方法已被弃用。因此,如果您能够使用 iOS 9,那么在 Swift 中可以使用以下方法:

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
        let newOrientation = UIDevice.currentDevice().orientation
        switch newOrientation {
        case .LandscapeLeft:
            self.capturePreviewLayer?.connection.videoOrientation = .LandscapeLeft
        case .LandscapeRight:
            self.capturePreviewLayer?.connection.videoOrientation = .LandscapeRight
        case .Portrait, .Unknown, .FaceUp, .FaceDown:
            self.capturePreviewLayer?.connection.videoOrientation = .Portrait
        case .PortraitUpsideDown:
            self.capturePreviewLayer?.connection.videoOrientation = .PortraitUpsideDown
        }
        super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
    }
于 2016-04-25T14:49:18.077 回答
0
// layout iOS 8+ animated 
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context)
    {
         NSString *timingFunc = nil;
         switch ( [context completionCurve] )
         {
             case UIViewAnimationCurveEaseIn:    timingFunc = kCAMediaTimingFunctionEaseIn;          break;
             case UIViewAnimationCurveEaseInOut: timingFunc = kCAMediaTimingFunctionEaseInEaseOut;   break;
             case UIViewAnimationCurveEaseOut:   timingFunc = kCAMediaTimingFunctionEaseOut;         break;
             case UIViewAnimationCurveLinear:    timingFunc = kCAMediaTimingFunctionLinear;          break;
         }

         [CATransaction begin];
         [CATransaction setAnimationDuration:[context transitionDuration]];
         [CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:timingFunc]];
         [self updatePreviewLayer];
         [CATransaction commit];

         UIInterfaceOrientation toOrientation = [[UIApplication sharedApplication] statusBarOrientation];
         // layout ui if needed

    } completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
    {

    }];

    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
}

- (void)updatePreviewLayer
{
    CGAffineTransform transform = CGAffineTransformIdentity;
    switch ( UIDevice.currentDevice.orientation )
    {
        case UIDeviceOrientationLandscapeLeft:
            transform = CGAffineTransformRotate(transform, -M_PI_2);
        break;
        case UIDeviceOrientationLandscapeRight:
            transform = CGAffineTransformRotate(transform, M_PI_2);
        break;
        case UIDeviceOrientationPortraitUpsideDown:
            transform = CGAffineTransformRotate(transform, M_PI);
        break;
        default:
        break;
    }
    preview.affineTransform = transform;
    preview.frame = self.view.bounds;
}
于 2016-05-05T14:34:01.920 回答