8

私のアプリには、特定のビュー コントローラーがあり、iPad (より具体的には通常の水平サイズ クラス) ではそれらをポップオーバーとして表示するのが理にかなっていますが、iPhone (またはコンパクトな水平サイズ クラス) ではプッシュするのが理にかなっていますそれらをナビゲーション スタックに追加します。これをサポートするエレガントな方法はありますか? デフォルトでは、「Present as Popover」セグエを使用すると、iPhone でモーダルに表示されますが、これは私が望むものではありません。

必要な動作を取得する方法を見つけましたが、見苦しく、エラーが発生しやすいようです。現在使用しているクラスのサイズに基づいて、2 つの異なるセグエから選択します。iOS 9 のマルチタスクをサポートするために[UIViewController willTransitionToTraitCollection:withTransitionCoordinator]、ビュー コントローラーを実装し、ポップオーバーとナビゲーション コントローラーの間で手動で移動します (この部分は特にエラーが発生しやすいようです)。

これを処理するためのカスタム セグエ、またはある種のカスタム アダプティブ プレゼンテーション コントローラーのいずれかを実装する簡単な方法があるはずですが、私はそれに頭を悩ませることができませんでした。誰もこれを成功させましたか?

4

2 に答える 2

2

私によると、これは最も簡単な方法です。

ステップ 1: 1 つのコントローラーから別のコントローラーへの 2 つのセグエを作成します。
ステップ 2:
1つのセグエのセグエ プロパティをプッシュして別のセグエ プロパティをポップオーバーするように設定します

これがサンプルコードです

サンプル コード 注: bool 条件を false に変更して、 の別の条件をチェックしdidSelectRowAtIndexPathます。

于 2015-08-28T13:01:13.937 に答える
1

これが私が最終的に構築したものです。あまり満足していないので、今まで投稿していませんでした。同じクラスのコントローラーを表示する 2 つのセグエはサポートされず、ポップオーバーのソース rect とソース ビューを自分で追跡する必要があります。しかし、おそらくそれは他の誰かにとって良い出発点になるでしょう.

PushPopoverSegue.swift

import UIKit

class PushPopoverSegue: UIStoryboardSegue {

    var sourceBarButtonItem: UIBarButtonItem!
    var permittedArrowDirections: UIPopoverArrowDirection = .Any

    override func perform() {
        assert( self.sourceViewController.navigationController != nil )
        assert( self.sourceBarButtonItem != nil )

        if self.sourceViewController.traitCollection.horizontalSizeClass == .Compact {
            self.sourceViewController.navigationController!.pushViewController(self.destinationViewController, animated: true)
        }
        else {
            let navigationController = UINavigationController(rootViewController: self.destinationViewController)
            let popover = UIPopoverController(contentViewController: navigationController)
            popover.presentPopoverFromBarButtonItem(self.sourceBarButtonItem, permittedArrowDirections: self.permittedArrowDirections, animated: true)
        }
    }

}

UIViewController+PushPopoverTransition.h

#import <UIKit/UIKit.h>

@interface UIViewController (PushPopoverTransition)

- (void) transitionPushPopoversToHorizontalSizeClass: (UIUserInterfaceSizeClass) sizeClass withMapping: (NSDictionary*) mapping;

@end

UIViewController+PushPopoverTransition.m

#import "UIViewController+PushPopoverTransition.h"

@implementation UIViewController (PushPopoverTransition)

- (void) transitionPushPopoversToHorizontalSizeClass: (UIUserInterfaceSizeClass) sizeClass withMapping: (NSDictionary*) mapping
{
    if ( sizeClass == UIUserInterfaceSizeClassCompact )
    {
        if ( self.presentedViewController == nil )
            return;

        NSParameterAssert( [self.presentedViewController isKindOfClass:[UINavigationController class]] );
        UINavigationController* navigationController = (UINavigationController*) self.presentedViewController;
        NSArray* viewControllers = navigationController.viewControllers;
        UIViewController* topOfStack = viewControllers[0];

        if ( [mapping.allKeys containsObject:NSStringFromClass( [topOfStack class] ) ] )
        {
            [self.presentedViewController dismissViewControllerAnimated:NO completion:^{
                for ( UIViewController* viewController in viewControllers )
                    [self.navigationController pushViewController:viewController animated:NO];
            }];
        }
    }
    else if ( sizeClass == UIUserInterfaceSizeClassRegular )
    {
        NSUInteger indexOfSelf = [self.navigationController.viewControllers indexOfObject:self];

        if ( indexOfSelf < self.navigationController.viewControllers.count  - 1 )
        {
            UIViewController* topOfStack = self.navigationController.viewControllers[indexOfSelf + 1];
            if ( [mapping.allKeys containsObject:NSStringFromClass( [topOfStack class] )] )
            {
                NSArray* poppedControllers = [self.navigationController popToViewController:self animated:NO];
                UINavigationController* navigationController = [[UINavigationController alloc] init];
                navigationController.modalPresentationStyle = UIModalPresentationPopover;
                navigationController.viewControllers = poppedControllers;

                id popoverSource = mapping[NSStringFromClass( [topOfStack class] )];
                if ( [popoverSource isKindOfClass:[UIBarButtonItem class]] )
                {
                    navigationController.popoverPresentationController.barButtonItem = popoverSource;
                }
                else if ( [popoverSource isKindOfClass:[NSArray class]] )
                {
                    NSArray* popoverSourceArray = (NSArray*) popoverSource;
                    NSParameterAssert(popoverSourceArray.count == 2);
                    UIView* sourceView = popoverSourceArray[0];
                    CGRect sourceRect = [(NSValue*) popoverSourceArray[1] CGRectValue];
                    navigationController.popoverPresentationController.sourceView = sourceView;
                    navigationController.popoverPresentationController.sourceRect = sourceRect;
                }

                [self presentViewController:navigationController animated:NO completion:nil];
            }
        }
    }
}

@end

使用例

インターフェイスビルダーでセグエを作成し、その「Kind」を Custom に、「Class」を に設定しPushPopoverSegueます。

ViewController.m

- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    ((PushPopoverSegue*) segue).sourceView = /* source view */;
    ((PushPopoverSegue*) segue).sourceRect = /* source rect */;
}

-(void) willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
    if ( newCollection.horizontalSizeClass == UIUserInterfaceSizeClassUnspecified )
        return;

    [self transitionPushPopoversToHorizontalSizeClass:newCollection.horizontalSizeClass withMapping:@{
        @"MyDestinationViewController": @[ /* source view */,
                                       [NSValue valueWithCGRect:/* source rect*/] ]
    }];
}
于 2016-02-07T04:10:45.353 に答える