ios 我如何创建一个在iPad上使用弹出框的segue,并推送到iPhone上的导航堆栈?

9jyewag0  于 5个月前  发布在  iOS
关注(0)|答案(3)|浏览(78)

在我的应用程序中,iPad上有某些视图控制器,(或者更具体地说,一个常规的水平大小类)将它们呈现为popovers是有意义的,但在iPhone上(或者一个紧凑的水平大小的类)将它们推到导航堆栈上是有意义的。有没有一种优雅的方法来支持这一点?默认情况下,如果我使用“PresentasPopover”,它将在iPhone上显示模式,这不是我想要的。
我已经找到了一种方法来获得我想要的行为,但它很难看,似乎容易出错。我根据我当前所在的大小类在两个不同的segue之间进行选择。为了支持iOS 9多任务处理,我实现了[UIViewController willTransitionToTraitCollection:withTransitionCoordinator],并手动将视图控制器在弹出框和导航控制器之间移动(这部分似乎特别容易出错)。
看起来应该有一些简单的方法来实现一个自定义的segue来处理这个问题,或者某种自定义的自适应演示控制器,但是我还没有能够把我的头绕过去。有人成功地做到了吗?

ukqbszuj

ukqbszuj1#

据我所知,这是最简单的方法,

**第1步:**创建两个从一个控制器到另一个控制器的segue。
**第二步:**将一个segue的segue属性设置为另一个segue的push和popover
**步骤3:**现在根据您的要求调用执行segue,即iPad或iPhone

这里是a sample code

示例代码注意:将bool condition改为false,检查didSelectRowAtIndexPath中的另一个条件。

7kjnsjlb

7kjnsjlb2#

这是我最终构建的。我对它不是很满意,这就是为什么我直到现在才发布它。它不支持两个segue去查看具有相同类的控制器,并且它需要你自己跟踪弹出窗口的源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+ PushPoverTransition.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

用法示例

在接口构建器中创建一个segue,并将其“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*/] ]
    }];
}

7xllpg7q

7xllpg7q3#

对于iOS 17,我只是在故事板中配置了一个Popover segue,然后在呈现视图控制器中这样做:

- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)animated completion:(void (^)(void))completion {
    if ( UIDevice.currentDevice.userInterfaceIdiom != UIUserInterfaceIdiomPad )
        [self.navigationController pushViewController:viewControllerToPresent animated:animated];
    else
        [super presentViewController:viewControllerToPresent animated:animated completion:completion];
}

字符串
似乎可以工作;不确定这在早期的SDK版本中是否可行。

相关问题