我正在研究实现自定义弹出对话框,如下图所示,并且遇到了各种方法来实现这一目标。
1-调用位于屏幕外部的View
,为当前视图层次结构添加叠加层,并将其设置为屏幕中心的动画
2-使用需要大量代码的UIPresentationController
3-使用吊舱
我想知道iOS中这类弹出窗口的当前状态,哪些是最简单,最直接的实现。
我正在寻找一个彻底比较现有选项的答案,并清楚地展示了每个选项的优缺点。
答案 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。
结果:
它肯定比UIView更复杂,但是不需要弄乱应用程序的UIWindow,或者要求UIWindow的RootViewController将我们的popover添加为子视图。如果您有任何疑问,请告诉我。