UIPresentationControllerでポップアップを作る
やりたいこと
UIAlertControllerではできないようなレイアウトを作る場合、
独自ポップアップにする必要があります。
例では背景を押したら閉じる挙動にしています。
どうつくるか
UIPresentationControllerを使います。
一般的なポップアップの動きにしたいので、
UIViewControllerAnimatedTransitioningでアニメーションも調整します
つくりかた
UIPresentationControllerのサブクラスを作る
#import <UIKit/UIKit.h> @interface PopPresentationController : UIPresentationController @end
#import "PopPresentationController.h" @interface PopPresentationController(){ } @property (nonatomic) UIView *overlayView; @end @implementation PopPresentationController - (void)presentationTransitionWillBegin { [super presentationTransitionWillBegin]; self.overlayView = [[UIView alloc]init]; // 表示トランジション開始前の処理 self.overlayView.frame = self.containerView.bounds; self.overlayView.backgroundColor = [UIColor blackColor]; self.overlayView.alpha = 0.0; [self.containerView insertSubview:self.overlayView atIndex:0]; id <UIViewControllerTransitionCoordinator> coordinator = [self.presentedViewController transitionCoordinator]; [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) { self.overlayView.alpha = 0.5; } completion:nil]; } - (void)dismissalTransitionWillBegin { [super dismissalTransitionWillBegin]; // 非表示トランジション開始前の処理 id <UIViewControllerTransitionCoordinator> coordinator = [self.presentedViewController transitionCoordinator]; [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) { self.overlayView.alpha = 0.0; } completion:nil]; } - (void)dismissalTransitionDidEnd:(BOOL)completed { [super dismissalTransitionDidEnd:completed]; // 非表示トランジション終了時の処理 if (completed){ [self.overlayView removeFromSuperview]; } } - (CGRect)frameOfPresentedViewInContainerView { return self.containerView.bounds; } - (void)containerViewWillLayoutSubviews { [super containerViewWillLayoutSubviews]; // レイアウト開始前の処理 self.overlayView.frame = self.containerView.bounds; self.presentedView.frame = self.frameOfPresentedViewInContainerView; } @end
UIViewControllerAnimatedTransitioningの実装クラスを作る
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @interface DialogAnimationController : NSObject<UIViewControllerAnimatedTransitioning> @property BOOL forPresented; - (id)init:(BOOL)forPresented; @end
#import "DialogAnimationController.h" @interface DialogAnimationController() @end @implementation DialogAnimationController - (id)init:(BOOL)forPresented { self.forPresented = forPresented; return self; } // アニメーション時間 - (NSTimeInterval)transitionDuration:(nullable id<UIViewControllerContextTransitioning>)transitionContext { return 0.2; } - (void)animateTransition:(nonnull id<UIViewControllerContextTransitioning>)transitionContext { if (self.forPresented) { [self presentAnimateTransition:transitionContext]; } else { [self dismissAnimateTransition:transitionContext]; } } // 表示時に使用するアニメーション - (void)presentAnimateTransition:(nonnull id<UIViewControllerContextTransitioning>)transitionContext { UIViewController *viewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIView *containerView = transitionContext.containerView; [containerView addSubview:viewController.view]; viewController.view.alpha = 0.0; viewController.view.transform = CGAffineTransformMakeScale(0.8, 0.8); [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0f options:UIViewAnimationOptionCurveEaseOut animations:^{ viewController.view.alpha = 1.0; viewController.view.transform = CGAffineTransformIdentity; } completion:^(BOOL finished) { [transitionContext completeTransition:YES]; }]; } // 非表示時に使用するアニメーション - (void)dismissAnimateTransition:(nonnull id<UIViewControllerContextTransitioning>)transitionContext { UIViewController *viewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0f options:UIViewAnimationOptionCurveEaseOut animations:^{ viewController.view.alpha = 0.0; } completion:^(BOOL finished) { [transitionContext completeTransition:YES]; }]; } @end
ポップアップ用のViewControllerをつくる
storybordには閉じる用のボタンを画面全体に配置
#import <UIKit/UIKit.h> @interface SamplePopUpViewController : UIViewController<UIViewControllerTransitioningDelegate> @end
#import "SamplePopUpViewController.h" #import "PopPresentationController.h" #import "DialogAnimationController.h" @interface SamplePopUpViewController () { BOOL initContent; } @property (weak, nonatomic) IBOutlet UIView *popview; @end @implementation SamplePopUpViewController - (id)initWithCoder:(NSCoder*)decoder { self = [super initWithCoder:decoder]; self.transitioningDelegate = self; self.modalPresentationStyle = UIModalPresentationCustom; if (!self) { return nil; } // write something. return self; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. } - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; if (initContent){ return; } initContent = YES; _popview.layer.cornerRadius = 22.0; } - (IBAction)closeButtonAction:(id)sender { [self dismissViewControllerAnimated:YES completion:nil]; } - (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source { return [[PopPresentationController alloc]initWithPresentedViewController:presented presentingViewController:presenting]; } - (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source { return [[DialogAnimationController alloc] init:YES]; } - (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed { return [[DialogAnimationController alloc] init:NO]; } @end
つかいかた
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"SamplePopUp" bundle:nil]; SamplePopUpViewController *viewcontroller = [storyboard instantiateViewControllerWithIdentifier:@"SamplePopUp"]; [self presentViewController:viewcontroller animated:YES completion:nil];