3

モーダル ポップアップ ダイアログを表示する簡単なビュー コントローラーを作成しました。画面全体に配置する新しいウィンドウを作成するため、 をUIDeviceOrientationDidChangeNotification使用してビューを回転する方法を把握するオブザーバーを追加しましたCGAffineTransformMakeRotation()。そしてそれはうまくいくようです。

多くの場合。欠点は、向きをいじって横向きにしたり逆さまにしたりできることです。この問題を示すこの 18 年代のビデオをチェックしてください。デバッグでは、通知が発生しないか、少なくともそれをリッスンしているコールバック メソッドを呼び出さないことがあるようです。

ビデオをもう一度見ると、後ろのビューが適切に回転していることに気付くでしょう。その 1 つがによって管理され-willAnimateRotationToInterfaceOrientation:duration:ます。iOS コントローラー メソッドが常に適切に呼び出される (おそらくUIDeviceOrientationDidChangeNotificationUIViewController のオブザーバーによって管理される) のに、自分のコードが正しくないのはなぜですか?

4

3 に答える 3

12

UIApplicationWillChangeStatusBarOrientationNotificationトリックを行うように見えるKoboで使用しました。必ずしもデバイスがたまたまどこにあるかではなく、UI の選択された向きに一致させたいため、はるかに信頼性が高くなります。つまり、ウィンドウの向きを変更するタイミングを Apple に決定させることができます。

iPad での Kobo アプリのポップアップ ダイアログ コードの一部を次に示します (iPad では UIAlertView が見栄えが悪いので、Richard Pennerがより良いコードを作成しました)。最新の iOS バージョンでいくつかの不具合が発生し、これらのダイアログをさまざまな状況 (方向 IIRC のすべて) で表示する必要があったため、UIWindow 内に直接配置するように微調整する必要がありました。これは、すべての方向変換ロジックを複製することを意味しました。

このコードは、ビューが現在のウィンドウに直接ドロップされる UIViewController からのものです。

- (void) presentDialogWindow
{
    // register for orientation change notification
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(orientationWillChange:)
                                                 name: UIApplicationWillChangeStatusBarOrientationNotification
                                               object: nil];
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(orientationDidChange:)
                                                 name: UIApplicationDidChangeStatusBarOrientationNotification
                                               object: nil];
}

- (void) orientationWillChange: (NSNotification *) note
{
    UIInterfaceOrientation current = [[UIApplication sharedApplication] statusBarOrientation];
    UIInterfaceOrientation orientation = [[[note userInfo] objectForKey: UIApplicationStatusBarOrientationUserInfoKey] integerValue];
    if ( [self shouldAutorotateToInterfaceOrientation: orientation] == NO )
        return;

    if ( current == orientation )
        return;

    // direction and angle
    CGFloat angle = 0.0;
    switch ( current )
    {
        case UIInterfaceOrientationPortrait:
        {
            switch ( orientation )
            {
                case UIInterfaceOrientationPortraitUpsideDown:
                    angle = (CGFloat)M_PI;  // 180.0*M_PI/180.0 == M_PI
                    break;
                case UIInterfaceOrientationLandscapeLeft:
                    angle = (CGFloat)(M_PI*-90.0)/180.0;
                    break;
                case UIInterfaceOrientationLandscapeRight:
                    angle = (CGFloat)(M_PI*90.0)/180.0;
                    break;
                default:
                    return;
            }
            break;
        }
        case UIInterfaceOrientationPortraitUpsideDown:
        {
            switch ( orientation )
            {
                case UIInterfaceOrientationPortrait:
                    angle = (CGFloat)M_PI;  // 180.0*M_PI/180.0 == M_PI
                    break;
                case UIInterfaceOrientationLandscapeLeft:
                    angle = (CGFloat)(M_PI*90.0)/180.0;
                    break;
                case UIInterfaceOrientationLandscapeRight:
                    angle = (CGFloat)(M_PI*-90.0)/180.0;
                    break;
                default:
                    return;
            }
            break;
        }
        case UIInterfaceOrientationLandscapeLeft:
        {
            switch ( orientation )
            {
                case UIInterfaceOrientationLandscapeRight:
                    angle = (CGFloat)M_PI;  // 180.0*M_PI/180.0 == M_PI
                    break;
                case UIInterfaceOrientationPortraitUpsideDown:
                    angle = (CGFloat)(M_PI*-90.0)/180.0;
                    break;
                case UIInterfaceOrientationPortrait:
                    angle = (CGFloat)(M_PI*90.0)/180.0;
                    break;
                default:
                    return;
            }
            break;
        }
        case UIInterfaceOrientationLandscapeRight:
        {
            switch ( orientation )
            {
                case UIInterfaceOrientationLandscapeLeft:
                    angle = (CGFloat)M_PI;  // 180.0*M_PI/180.0 == M_PI
                    break;
                case UIInterfaceOrientationPortrait:
                    angle = (CGFloat)(M_PI*-90.0)/180.0;
                    break;
                case UIInterfaceOrientationPortraitUpsideDown:
                    angle = (CGFloat)(M_PI*90.0)/180.0;
                    break;
                default:
                    return;
            }
            break;
        }
    }

    CGAffineTransform rotation = CGAffineTransformMakeRotation( angle );

    [UIView beginAnimations: @"" context: NULL];
    [UIView setAnimationDuration: 0.4];
    self.view.transform = CGAffineTransformConcat(self.view.transform, rotation);
    [UIView commitAnimations];
}

- (void) orientationDidChange: (NSNotification *) note
{
    UIInterfaceOrientation orientation = [[[note userInfo] objectForKey: UIApplicationStatusBarOrientationUserInfoKey] integerValue];
    if ( [self shouldAutorotateToInterfaceOrientation: [[UIApplication sharedApplication] statusBarOrientation]] == NO )
        return;

    self.view.frame = [[UIScreen mainScreen] applicationFrame];

    [self didRotateFromInterfaceOrientation: orientation];
}

このビュー コントローラをロードし、そのビューをウィンドウに追加してから、次のように -presentModalDialog を呼び出して使用します。

UIView *window = [[UIApplication sharedApplication] keyWindow];
[window addSubview: theController.view];
[theController presentDialogWindow];

簡単な UIViewController サブクラスを作成して、面倒な部分をすぐに実装し、github アカウントに投稿する予定です。その際、これを編集してリンクします。

于 2011-02-17T02:06:23.737 に答える
0

の使用を排除することで、この問題を修正しましたUIDeviceOrientationDidChangeNotification。代わりに、のサブクラスを作成しUIViewController、カスタム ビューをそのビューに設定します。-willAnimateRotationToInterfaceOrientation:duration:次に、ローテーションを実行するために単に実装します。これは実際には、私にとってそれほど面倒なコードではありません。UIViewControllerただし、本質的に のクローンである自動回転を利用するためだけに任意の を作成するのはハックのように感じますpresentModalViewControllerUIDeviceOrientationDidChangeNotification適切に動作するはずのようです。動作させる方法があると思いますが、まだ見つけていません。:-(

于 2011-02-14T16:56:59.410 に答える
0

UIDeviceOrientation には、UIInterfaceOrientation にマップされない値がいくつかあります。

UIDeviceOrientationUnknown,
UIDeviceOrientationFaceUp,              // Device oriented flat, face up
UIDeviceOrientationFaceDown             // Device oriented flat, face down

通知コールバックが発生している可能性はありますが、これらのケースは処理されませんか?

ビュー コントローラがウィンドウにアクセスできる場合、didRotate コールバックを手動でウィンドウに転送できます。

于 2011-02-10T20:11:47.413 に答える