8

私のアプリケーションは、PortraitUpsideDown を除くすべての向きをサポートしています。私のビュー階層では、UIImageView であるトップ ビューのサブレイヤーとして AVCaptureVideoPreviewLayer があります。ビュー階層の下には、コントロールを表示するいくつかのオーバーレイ ビューがあります。

オーバーレイ ビューは向きを変更しても適切に機能していますが、この AVCaptureVideoPreviewLayer をどう扱うべきかわかりません。PreviewLayer が静止したままになり、コントロールがスムーズに再編成されるように、カメラ アプリのように動作させたいと考えています。現在、方向の変更時にメイン ビューが回転するため、プレビュー レイヤーも回転します。つまり、横向きビューでは縦向きビューのままで、画面の一部のみを取得し、カメラからの画像も 90 度回転します。プレビューレイヤーを手動で回転させることができましたが、この方向変更アニメーションがあり、アニメーション中にしばらくの間背景が表示されます。

では、previewLayer を静止させながらコントロールを自動回転させる適切な方法は何ですか?

4

3 に答える 3

5

私の実装では、回転させたいビューの UIView をサブクラス化し、NSObject の単なるサブクラスであるこのビューの viewController のようなものを作成しました。

このviewControllerでは、向きの変更に関連するすべてのチェックを行い、ターゲットビューの向きを変更する必要があるかどうかを決定し、そうであれば、向きを変更するためにビューのメソッドを呼び出します。

まず、アプリケーション インターフェース全体の向きをポートレート モードに修正する必要があります。これにより、ACCaptureVideoPreviewLayer が常に静止したままになります。これは で行われますMainViewController.h

(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation`
{
    return interfaceOrientation==UIInterfaceOrientationPortrait;
}

縦向き以外のすべての向きに対して NO を返します。

カスタム viewController がデバイスの向きの変化を追跡できるようにするには、対応する通知のオブザーバーにする必要があります。

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(orientationChanged) name:UIDeviceOrientationDidChangeNotification object:nil];

これらの行を(void)awakeFromNibviewControllerのメソッドに入れました。したがって、デバイスの向きが変更されるたびに、viewController のメソッドorientationChangedが呼び出されます。

その目的は、デバイスの新しい向きとデバイスの最後の向きを確認し、それを変更するかどうかを決定することです。実装は次のとおりです。

if(UIInterfaceOrientationPortraitUpsideDown==[UIDevice currentDevice].orientation ||
    lastOrientation==(UIInterfaceOrientation)[UIDevice currentDevice].orientation) 
    return;
    [[UIApplication sharedApplication]setStatusBarOrientation:[UIDevice currentDevice].orientation animated:NO];

    lastOrientation=[UIApplication sharedApplication].statusBarOrientation;
    [resultView orientationChanged];

向きが以前と同じ、または PortraitUpsideDown の場合は、何もしません。それ以外の場合は、ステータス バーの向きを適切な方向に設定して、着信や骨化があったときに画面の適切な側に表示されるようにします。そして、新しい方向に対応するこのビュー内のインターフェイスの他の要素を回転、サイズ変更、移動するなど、新しい方向に対応するすべての変更が行われるターゲットビューでもメソッドを呼び出します。

orientationChangedターゲットビュー内の実装は次のとおりです。

Float32 angle=0.f;
UIInterfaceOrientation orientation=[UIApplication sharedApplication].statusBarOrientation;

switch (orientation) {
    case UIInterfaceOrientationLandscapeLeft: 
        angle=-90.f*M_PI/180.f;
        break;
    case UIInterfaceOrientationLandscapeRight: 
            angle=90.f*M_PI/180.f;
        break;
    default: angle=0.f;
        break;
}   
if(angle==0 && CGAffineTransformIsIdentity(self.transform)) return;

CGAffineTransform transform=CGAffineTransformMakeRotation(angle);

[UIView beginAnimations:@"rotateView" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[UIView setAnimationDuration:0.35f];

self.transform=transform;

[UIView commitAnimations];

もちろん、ここでは、新しい向きに対応してアニメーション化する必要があるインターフェースのさまざまなビューの翻訳、スケーリングなどの他の変更を追加できます。

また、これにはviewControllerは必要ないかもしれませんが、ビューのクラスですべてを行います。一般的な考え方が明確であることを願っています。

また、次のような不要な向きの変更の通知を停止することを忘れないでください。

[[NSNotificationCenter defaultCenter]removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
[[UIDevice currentDevice]endGeneratingDeviceOrientationNotifications];
于 2012-10-28T11:35:17.520 に答える
1

iOS 8 ソリューション:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) {
        self.layer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeLeft;
    } else {
        self.layer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
    }
}

あなたのセットアップコードで:

self.layer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
self.layer.videoGravity = AVLayerVideoGravityResizeAspectFill;
if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) {
    self.layer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeLeft;
} else {
    self.layer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
}
于 2015-05-22T10:18:17.813 に答える
0

主な問題は、通知を受け取ったときにステータスバーがまだ回転していないため、現在の値を確認すると、実際には回転前の値が得られることです。そのため、statusbarorientation をチェックしてサブビューを回転させるメソッドを呼び出す前に、少し遅延 (ここでは 2 秒) を追加しました。

-(void) handleNotification:(NSNotification *) notification
{    
    (void) [NSTimer scheduledTimerWithTimeInterval:(2.0)
                                           target:self
                                          selector:@selector(orientationChanged)
                                          userInfo:nil
                                           repeats:NO ] ;
}

コードの残りの部分は BartoNaz のものです。

于 2012-12-21T17:46:04.760 に答える