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


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

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

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

22 153

22 ответа:

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

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

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

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

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

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

EDIT:

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

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

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

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

UIModalPresentationOverCurrentContext

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

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

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

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

"View Controller Advancements in iOS 8" видео с WWDC 2014 идет вдавайтесь в это поподробнее.

Примечание:

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

в iOS 8.0 и выше это можно сделать, установив свойство modalPresentationStyle до 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 file

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

M file

@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];

редактировать (работает на 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) не должны иметь одинаковый уровень/иерархию. Не делайте imageview дочерним видом в противном случае непрозрачность uiview повлияет на UIView (2))
  1. Присутствует V2 Модально

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

Storyboard

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

Storyboard

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

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

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