iOS: модальный ViewController с прозрачным фоном

Я пытаюсь представить контроллер представления модально, с прозрачным фоном. Моя цель состоит в том, чтобы одновременно отображать представление и представление контроллеров представления. Проблема в том, что когда анимация представления заканчивается, представление контроллера представления исчезает.

- (IBAction)pushModalViewControllerButtonPressed:(id)sender
{
    ModalViewController *modalVC = [[ModalViewController alloc] init];
    [self presentViewController:modalVC animated:YES completion:nil];
}

Я знаю, что могу просто добавить представление в качестве подвида, но я хотел бы избежать этого решения по какой-то причине. Как я могу это исправить?

22 ответов


следующий код работает только на iPad.

self.view.backgroundColor = [UIColor clearColor];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:modalVC animated:YES];

Я бы пошел с добавлением sub view.

вот очень хорошая дискуссия. Посмотрите на комментарии конкретно. Не только ответ.

Модальное Представление

на твоем месте я бы этого не делал. Я бы добавил sub view и сделал это. Кажется, это дает мне лучший контроль над вещами.

EDIT:

как упоминал пол Линсей, начиная с iOS 8 все, что нужно-это UIModalPresentationOverFullScreen для modalPresentationStyle представленного ViewController. Это также будет охватывать кнопки navigationBar и tabBar.


для тех, кто пытается заставить это работать в iOS 8," одобренный Apple " способ отображения прозрачного контроллера модального вида-установить modalPresentationStyle по настоящее времяЭд контроллер to UIModalPresentationOverCurrentContext.

Это можно сделать в коде, или установив свойства segue в раскадровке.

из документации UIViewController:

UIModalPresentationOverCurrentContext

A стиль презентации, в котором содержимое отображается только поверх содержимое контроллера родительского представления. Взгляды под представлены содержимое не удаляется из иерархии представлений при представлении заканчивает. Поэтому, если представленный контроллер вида не заполняет экран с непрозрачным содержимым, основное содержание показывает до конца.

при представлении контроллера вида в popover эта презентация стиль поддерживается, только если стиль перехода UIModalTransitionStyleCoverVertical. Попытка использовать другой стиль перехода вызывает исключение. Однако, вы можете использовать другие стили перехода (кроме частичного перехода curl), если родительский контроллер вида не находится в popover.

доступно в iOS 8.0 и более поздних версиях.

https://developer.apple.com/documentation/uikit/uiviewcontroller

"просмотр контроллера достижений в iOS 8" видео с WWDC 2014 идет в это в некоторых деталях.

Примечание:

  • обязательно дайте вашему представленному контроллеру вида четкий цвет фона, чтобы он на самом деле не был прозрачным!
  • вы должны установить этот до представление ie, устанавливающего этот параметр в viewDidLoad presentedViewController не будет иметь никакого влияния

в iOS 8.0 и выше это можно сделать, установив свойство modalPresentationStyle to UIModalPresentationOverCurrentContext

//Set property **definesPresentationContext** YES to avoid presenting over presenting-viewController's navigation bar

self.definesPresentationContext = YES; //self is presenting view controller
presentedController.view.backgroundColor = [YOUR_COLOR with alpha OR clearColor]
presentedController.modalPresentationStyle = UIModalPresentationOverCurrentContext;

[self presentViewController:presentedController animated:YES completion:nil];

See Image Attached


этот код отлично работает на iPhone под iOS6 и iOS7:

presentedVC.view.backgroundColor = YOUR_COLOR; // can be with 'alpha'
presentingVC.modalPresentationStyle = UIModalPresentationCurrentContext;
[presentingVC presentViewController:presentedVC animated:YES completion:NULL];

в этом случае вы пропустите слайд-анимации. Чтобы сохранить анимацию, вы все равно можете использовать следующее" неэлегантное " расширение:

[presentingVC presentViewController:presentedVC animated:YES completion:^{
    [presentedVC dismissViewControllerAnimated:NO completion:^{
        presentingVC.modalPresentationStyle = UIModalPresentationCurrentContext;
        [presentingVC presentViewController:presentedVC animated:NO completion:NULL];
    }];
}];

если наш presentingV находится внутри UINavigationController или UITabbarController, вам нужно работать с этими контроллерами как presentingVC.

далее, в iOS7 вы можете реализовать пользовательскую анимацию перехода, применяя UIViewControllerTransitioningDelegate протокол. Из конечно, в этом случае вы можете сделать прозрачный фон

@interface ModalViewController : UIViewController <UIViewControllerTransitioningDelegate>

во-первых, перед представлением вы должны установить modalPresentationStyle

modalViewController.modalPresentationStyle = UIModalPresentationCustom;

тогда вы должны реализовать два метода протокола

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
    CustomAnimatedTransitioning *transitioning = [CustomAnimatedTransitioning new];
    transitioning.presenting = YES;
    return transitioning;
}

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
    CustomAnimatedTransitioning * transitioning = [CustomAnimatedTransitioning new];
    transitioning.presenting = NO;
    return transitioning;
}

последнее, что нужно определить свой пользовательский переход в CustomAnimatedTransitioning класс

@interface CustomAnimatedTransitioning : NSObject <UIViewControllerAnimatedTransitioning>
@property (nonatomic) BOOL presenting;
@end

@implementation CurrentContextTransitionAnimator

- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext 
{
    return 0.25;
}

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext 
{
    UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

    if (self.presenting) {
        // custom presenting animation
    }
    else {
        // custom dismissing animation
    }
}

создайте сегмент для представления модально и установите свойство представления этого сегмента в текущий контекст он будет работать 100 %

enter image description here


Я немного боролся с построителем интерфейса XCode 7, чтобы установить стиль презентации, как предложил @VenuGopalTewari. В этой версии, кажется, нет Over Current Context или Over Full Screen режим презентации для segue. Таким образом, чтобы заставить его работать, я установил режим Default:

enter image description here С enter image description here

дополнительно я установил режим представления модально представленного контроллера вида на Over Full Screen:

enter image description here


PresentViewController с прозрачным фоном-в iOS 8 и iOS 9

MYViewController *myVC = [self.storyboard   instantiateViewControllerWithIdentifier:@"MYViewController"];
    myVC.providesPresentationContextTransitionStyle = YES;
    myVC.definesPresentationContext = YES;
    [myVC setModalPresentationStyle:UIModalPresentationOverCurrentContext];
    [self.navigationController presentViewController:myVC animated:YES completion:nil];

и в MYViewController установите цвет фона черный и уменьшите непрозрачность


это немного хакерский способ, но для меня этот код работает (iOS 6):

AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

[self presentViewController:self.signInViewController animated:YES completion:^{
    [self.signInViewController dismissViewControllerAnimated:NO completion:^{
        appDelegate.window.rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
        [self presentViewController:self.signInViewController animated:NO completion:nil];
        appDelegate.window.rootViewController.modalPresentationStyle = UIModalPresentationFullScreen;

    }];
}];

этот код работает также на iPhone


эта категория работала для меня (ios 7, 8 и 9)

H файл

@interface UIViewController (navigation)
- (void) presentTransparentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion;
@end

M файл

@implementation UIViewController (navigation)
- (void)presentTransparentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion
{
    if(SYSTEM_VERSION_LESS_THAN(@"8.0")) {
        [self presentIOS7TransparentController:viewControllerToPresent withCompletion:completion];

    }else{
        viewControllerToPresent.modalPresentationStyle = UIModalPresentationOverCurrentContext;
         [self presentViewController:viewControllerToPresent animated:YES completion:completion];
    }
}
-(void)presentIOS7TransparentController:(UIViewController *)viewControllerToPresent withCompletion:(void(^)(void))completion
{
    UIViewController *presentingVC = self;
    UIViewController *root = self;
    while (root.parentViewController) {
        root = root.parentViewController;
    }
    UIModalPresentationStyle orginalStyle = root.modalPresentationStyle;
    root.modalPresentationStyle = UIModalPresentationCurrentContext;
    [presentingVC presentViewController:viewControllerToPresent animated:YES completion:^{
        root.modalPresentationStyle = orginalStyle;
    }];
}
@end

я добавил Эти три строки в init метод в-представление-контроллер, и работает как шарм:

self.providesPresentationContextTransitionStyle = YES;
self.definesPresentationContext = YES;
[self setModalPresentationStyle:UIModalPresentationOverCurrentContext];

EDIT (работает на iOS 9.3):

self.modalPresentationStyle = UIModalPresentationOverFullScreen;

согласно документации:

UIModalPresentationOverFullScreen Стиль представления вида, в котором представленный вид охватывает экран. Представления под представленным содержимым не удаляются из иерархии представлений по завершении представления. Так если представленный контроллер вида не заполняет экран непрозрачным содержимым, основное содержимое отображается насквозь.

доступно в iOS 8.0 и более поздних версиях.


альтернативный способ-использовать "вид контейнера". Просто сделайте Альфа ниже 1 и добавьте seque. XCode 5, цель iOS7. Проверено на iPhone.

enter image description here

вид контейнера доступен из iOS6. ссылке в блоге об этом.


Если вы используете раскадровку, вы можете выполнить следующий шаг:

  1. добавить контроллер вида (V2), настроить пользовательский интерфейс так, как вы хотите его
  • добавить фон UIView-установить черный и непрозрачность до 0,5
  • добавить другой UIView (2) - который будет служить в качестве всплывающего окна(Пожалуйста, обратите внимание, что UIView и UIView (2) не должны иметь тот же уровень/иерархию. Dont сделать графическое представление ребенка считает иначе непрозрачность uiview повлияет на UIView (2))
  1. Присутствует V2 Модально

  2. щелкните по сегменту. В инспекторе атрибутов задайте представление как На Весь Экран. Удалить анимацию, если вам нравится

Storyboard

  1. Выберите V2. В инспекторе атрибутов задайте представление как На Весь Экран. Проверка определяет контекст и Предоставляет Контекст

Storyboard

  1. выберите MainView вашего V2 (Pls. Проверьте изображение). Установите backgroundColor в Ясный Цвет

Storyboard


Я создал объект для обработки представления того, что я называю "наложенным модальным", то есть он сохраняет вид фона и позволяет вам иметь модальный с прозрачным фоном.

он имеет один простой метод, который делает это:

- (void)presentViewController:(UIViewController *)presentedViewController
       fromViewController:(UIViewController *)presentingViewController
{
    presentedViewController.modalPresentationStyle = UIModalPresentationCustom;
    presentedViewController.transitioningDelegate = self;
    presentedViewController.modalPresentationCapturesStatusBarAppearance = YES;

    [presentedViewController setNeedsStatusBarAppearanceUpdate];

    [presentingViewController presentViewController:presentedViewController
                                       animated:YES
                                     completion:nil];
}

важно установить modalPresentationCapturesStatusBarAppearance свойство YES сила и статус бар внешности обновить, если представлен вид контроллера имеет разное preferredStatusBarStyle.

этот объект должен есть @property (assign, nonatommic) isPresenting

вы хотите, чтобы этот объект соответствовал UIViewControllerAnimatedTransitioning и UIViewControllerTransitioningDelegate протоколы и реализовать следующие методы:

- (id)animationControllerForPresentedController:(UIViewController *)presented
                           presentingController:(UIViewController *)presenting
                               sourceController:(UIViewController *)source
{
    self.isPresenting = YES;

    return self;
}

- (id)animationControllerForDismissedController:(UIViewController *)dismissed
{
    self.isPresenting = NO;

    return self;
}

и:

- (NSTimeInterval)transitionDuration:(id)transitionContext
{
    return 0.25;
}

- (void)animateTransition:(id)transitionContext
{
    UIViewController* firstVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController* secondVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIView* containerView = [transitionContext containerView];
    UIView* firstView = firstVC.view;
    UIView* secondView = secondVC.view;

    if (self.isPresenting) {
        [containerView addSubview:secondView];
        secondView.frame = (CGRect){
            containerView.frame.origin.x,
            containerView.frame.origin.y + containerView.frame.size.height,
            containerView.frame.size
        };

        firstView.tintAdjustmentMode = UIViewTintAdjustmentModeDimmed;
        [UIView animateWithDuration:0.25 animations:^{
            secondView.frame = containerView.frame;
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:YES];
        }];
        } else {
        [UIView animateWithDuration:0.25 animations:^{
            firstView.frame = (CGRect){
                containerView.frame.origin.x,
                containerView.frame.origin.y + containerView.frame.size.height,
                containerView.frame.size
        };

        } completion:^(BOOL finished) {
            [transitionContext completeTransition:YES];
        }];
    }
}

это делает слайд-в-снизу анимации имитируя модальную анимацию по умолчанию, но вы можете сделать это все, что вы хотите.

важно то, что представление контроллера представления будет оставаться в задней части, позволяя вам создать прозрачный эффект.

это решение работает для iOS 7+


очень простой способ сделать это (используя Storyboards, например):

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"SomeStoryboard" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"SomeStoryboardViewController"];
// the key for what you're looking to do:
vc.modalPresentationStyle = UIModalPresentationOverCurrentContext;
vc.view.alpha = 0.50f;

[self presentViewController:vc animated:YES completion:^{
    // great success
}];

это UIViewController на Storyboard модально, но с прозрачным фоном.


чтобы резюмировать все хорошие ответы и комментарии здесь и по-прежнему иметь анимацию при переходе на новый ViewController вот что я сделал: (поддерживает iOS 6 и выше)

если вы используете UINavigationController \ UITabBarController этот путь:

    SomeViewController *vcThatWillBeDisplayed = [self.storyboard instantiateViewControllerWithIdentifier:@"SomeVC"];

    vcThatWillBeDisplayed.view.backgroundColor = [UIColor colorWithRed: 255/255.0 green:255/255.0 blue:255/255.0 alpha:0.50];    

    self.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
    [self presentViewController:presentedVC animated:YES completion:NULL];

если вы сделаете это, вы потеряете свой modalTransitionStyle анимация. Для того, чтобы решить его, вы можете легко добавить в свой SomeViewController класс:

-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [UIView animateWithDuration:0.4 animations:^() {self.view.alpha = 1;}
       completion:^(BOOL finished){}];
}
- (void)viewDidLoad
{
    [super viewDidLoad];
    self.view.alpha = 0;
}

Работа для iOS 7-10

if #available(iOS 8.0, *) {
    nextVC.modalPresentationStyle = .OverCurrentContext
    self.presentViewController(nextVC, animated: true, completion: nil)
} else {
    // Fallback on earlier version
    self.modalPresentationStyle = .Custom          
    nextVC.modalTransitionStyle = .CrossDissolve            
    self.presentViewController(nextVC, animated: false, completion: nil)
    }
}

решение этого ответа с использованием swift будет следующим.

let vc = MyViewController()
vc.view.backgroundColor = UIColor.clear // or whatever color.
vc.modalPresentationStyle = .overCurrentContent
present(vc, animated: true, completion: nil)

Если вы используете модальный сегмент, обязательно установите его как это изображение (вы можете отключить анимацию, если хотите)enter image description here


полный метод, протестированный на iOS 7 и iOS 8.

@interface UIViewController (MBOverCurrentContextModalPresenting)

/// @warning Some method of viewControllerToPresent will called twice before iOS 8, e.g. viewWillAppear:.
- (void)MBOverCurrentContextPresentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion;

@end

@implementation UIViewController (MBOverCurrentContextModalPresenting)

- (void)MBOverCurrentContextPresentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
    UIViewController *presentingVC = self;

    // iOS 8 before
    if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1) {
        UIViewController *root = presentingVC;
        while (root.parentViewController) {
            root = root.parentViewController;
        }

        [presentingVC presentViewController:viewControllerToPresent animated:YES completion:^{
            [viewControllerToPresent dismissViewControllerAnimated:NO completion:^{
                UIModalPresentationStyle orginalStyle = root.modalPresentationStyle;
                if (orginalStyle != UIModalPresentationCurrentContext) {
                    root.modalPresentationStyle = UIModalPresentationCurrentContext;
                }
                [presentingVC presentViewController:viewControllerToPresent animated:NO completion:completion];
                if (orginalStyle != UIModalPresentationCurrentContext) {
                    root.modalPresentationStyle = orginalStyle;
                }
            }];
        }];
        return;
    }

    UIModalPresentationStyle orginalStyle = viewControllerToPresent.modalPresentationStyle;
    if (orginalStyle != UIModalPresentationOverCurrentContext) {
        viewControllerToPresent.modalPresentationStyle = UIModalPresentationOverCurrentContext;
    }
    [presentingVC presentViewController:viewControllerToPresent animated:YES completion:completion];
    if (orginalStyle != UIModalPresentationOverCurrentContext) {
        viewControllerToPresent.modalPresentationStyle = orginalStyle;
    }
}

@end

в appdelegate:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [[_window rootViewController]setModalPresentationStyle:UIModalPresentationCurrentContext];
    return YES;
}

в вас контроллер первого вида, откуда вы должны загрузить следующий вид:

  NextViewController *customvc = [[NextViewController alloc]init];
    [self presentViewController:customvc animated:YES completion:^{

    }];

в вашем nextViewController, который должен быть добавлен прозрачный:

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor clearColor];
    UIView* backView = [[UIView alloc] initWithFrame:self.view.frame];
    backView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6];
    [self.view insertSubview:backView atIndex:0];
}

экран входа в систему является модальным, что означает, что он находится поверх предыдущего экрана. До сих пор у нас был размытый фон, но это ничего не размывает; это просто серый фон.

нам нужно установить наш модальный должным образом.

ссылка на изображение элемент

  • во-первых, нам нужно изменить фон представления контроллера вида, чтобы очистить цвет. Это просто означает, что она должна быть прозрачной. По умолчанию это представление белый.

  • во-вторых, нам нужно выбрать сегмент, который ведет к экрану входа в систему, и в Инспекторе атрибутов установите презентацию в текущий контекст. Этот параметр доступен только с включенными классами Auto Layout и Size.

ссылка на изображение элемент


установка навигации modalPresentationStyle до UIModalPresentationCustom

и установите цвет фона вашего представленного контроллера вида как чистый цвет.