自定义弹出对话框

时间:2015-12-08 19:55:15

标签: ios cocoa-touch uikit

我正在研究实现自定义弹出对话框,如下图所示,并且遇到了各种方法来实现这一目标。

1-调用位于屏幕外部的View,为当前视图层次结构添加叠加层,并将其设置为屏幕中心的动画

2-使用需要大量代码的UIPresentationController

3-使用吊舱

我想知道iOS中这类弹出窗口的当前状态,哪些是最简单,最直接的实现。

我正在寻找一个彻底比较现有选项的答案,并清楚地展示了每个选项的优缺点。

enter image description here

1 个答案:

答案 0 :(得分:1)

如果你支持iOS 8及更高版本(你应该尽可能使用它!)我建议使用带有UIPresentationController的UIViewController在后台处理幕布视图。

我的理由:

•这些都是非常新的100%原生API。

•Apple对自己的一些API(参见UIAlertController)进行了有趣的更改,他们已经从UIView / UIControl转换为UIViewControllers。

我应该注意到UIViewController在这里可能过度,因为我觉得popover非常简单。不过,实施起来也很简单。

这里有一些UIViewController的示例代码我提出:

SecondViewController是popover:

#import "SecondViewController.h"
#import "SecondPresentationController.h"

@interface SecondViewController () <UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning>

@property (nonatomic, getter=isPresenting) BOOL presenting;

@end


@implementation SecondViewController

#pragma mark - Initialization

- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {

    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

    if (self) {

        self.transitioningDelegate = self;
        self.modalPresentationStyle = UIModalPresentationCustom;
        self.view.layer.cornerRadius = 5.0f;
        self.view.clipsToBounds = YES;
    }

    return self;
}


#pragma mark - Content Size

- (CGSize)preferredContentSize {

    return CGSizeMake(266.0f, 143.0f); // The static size of the test image I'm using for this sample code.
}


#pragma mark - UIViewControllerTransitioningDelegate

- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {

    return 1.0;
}

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {

    self.presenting = YES; /// Used in animateTransition

    return self;
}


- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {

    self.presenting = NO; /// Used in animateTransition

    return self;
}


- (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source {

    return [[SecondPresentationController alloc] initWithPresentedViewController:self presentingViewController:self.presentingViewController];
}


#pragma mark - UIViewControllerAnimatedTransitioning

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {

    UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

    [[transitionContext containerView] addSubview:toViewController.view];

    CGSize preferredSize = toViewController.preferredContentSize;

    // onscreenFrame will be in the center of the superview, while offscreen will be just below the superview (and off of the screen completely)

    CGRect onscreenFrame = CGRectMake((fromViewController.view.bounds.size.width - preferredSize.width) * 0.5f, (fromViewController.view.bounds.size.height - preferredSize.height) * 0.5f,
                                      preferredSize.width, preferredSize.height);

    CGRect offscreenFrame = onscreenFrame;

    offscreenFrame.origin.y = fromViewController.view.bounds.size.height;

    // Set the *initial* frame for the viewController.

    if (self.isPresenting) {

        toViewController.view.frame = offscreenFrame;
    }
    else {

        toViewController.view.frame = onscreenFrame;
    }

    [UIView animateWithDuration:0.5 delay:0.0 usingSpringWithDamping:0.8f initialSpringVelocity:0.8f options:kNilOptions animations:^{

        // Now animate to the final frame.
        if (self.isPresenting) {

            toViewController.view.frame = onscreenFrame;
        }
        else {

            toViewController.view.frame = offscreenFrame;
        }


    } completion:^(BOOL finished) {

        [transitionContext completeTransition:YES];
    }];


}

@end

SecondPresentationController处理幕后视图:

#import "SecondPresentationController.h"

@interface SecondPresentationController ()

@property (nonatomic, readonly) UIView *curtainView;

@end


@implementation SecondPresentationController

- (instancetype)initWithPresentedViewController:(UIViewController *)presentedViewController presentingViewController:(UIViewController *)presentingViewController {

    self = [super initWithPresentedViewController:presentedViewController presentingViewController:presentingViewController];

    if (self) {

        _curtainView = [UIView new];
        self.curtainView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.6f];
        self.curtainView.alpha = 0.0f;

    }

    return self;
}

- (void)presentationTransitionWillBegin {

    UIView *containerView = self.containerView;

    self.curtainView.frame = containerView.bounds;

    self.curtainView.alpha = 0.0f;

    [containerView insertSubview:self.curtainView atIndex:0];

    [self.presentedViewController.transitionCoordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {

        self.curtainView.alpha = 1.0f;
    } completion:nil];
}


@end

然后,您将正常呈现SecondViewController。

结果:

The result after presenting the popup. 它肯定比UIView更复杂,但是不需要弄乱应用程序的UIWindow,或者要求UIWindow的RootViewController将我们的popover添加为子视图。如果您有任何疑问,请告诉我。