Как использовать presentModalViewController для создания прозрачного представления


Я показываю модальный вид с

[self presentModalViewController:controller animated:YES];

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

есть ли в любом случае держать вид прозрачным?

Я подозреваю, что вид, на который он помещается, не визуализируется, а затем что модальное представление становится непрозрачным.

21 79

21 ответ:

ваш вид по-прежнему прозрачен, но как только ваш модальный контроллер находится в верхней части стека, вид за ним скрыт (как и в случае с любым самым верхним контроллером вида). Решение состоит в том, чтобы вручную анимировать представление самостоятельно; тогда behind-viewController не будет скрыт (так как вы не будете "оставлять" его).

после iOS 3.2 есть способ сделать это без каких-либо "хитростей" – см. документацию для свойства modalPresentationStyle. У вас есть rootViewController, который будет представлять viewController. Итак, вот код успеха:

viewController.view.backgroundColor = [UIColor clearColor];
rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
[rootViewController presentModalViewController:viewController animated:YES];

С помощью этого метода фон viewController будет прозрачным, а базовый rootViewController будет виден. обратите внимание, что это работает только на iPad, см. комментарии под.

что мне нужно, чтобы заставить это работать:

self.window.rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;

для тех, кто хочет увидеть какой-то код, вот что я добавил в контроллер моего прозрачного представления:

// Add this view to superview, and slide it in from the bottom
- (void)presentWithSuperview:(UIView *)superview {
    // Set initial location at bottom of superview
    CGRect frame = self.view.frame;
    frame.origin = CGPointMake(0.0, superview.bounds.size.height);
    self.view.frame = frame;
    [superview addSubview:self.view];            

    // Animate to new location
    [UIView beginAnimations:@"presentWithSuperview" context:nil];
    frame.origin = CGPointZero;
    self.view.frame = frame;
    [UIView commitAnimations];
}

// Method called when removeFromSuperviewWithAnimation's animation completes
- (void)animationDidStop:(NSString *)animationID
                finished:(NSNumber *)finished
                 context:(void *)context {
    if ([animationID isEqualToString:@"removeFromSuperviewWithAnimation"]) {
        [self.view removeFromSuperview];
    }
}

// Slide this view to bottom of superview, then remove from superview
- (void)removeFromSuperviewWithAnimation {
    [UIView beginAnimations:@"removeFromSuperviewWithAnimation" context:nil];

    // Set delegate and selector to remove from superview when animation completes
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];

    // Move this view to bottom of superview
    CGRect frame = self.view.frame;
    frame.origin = CGPointMake(0.0, self.view.superview.bounds.size.height);
    self.view.frame = frame;

    [UIView commitAnimations];    
}

одобренный Apple способ сделать это в iOS 8-установить modalPresentationStyle в 'UIModalPresentationOverCurrentContext'.

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

UIModalPresentationOverCurrentContext

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

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

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

https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/

видео "View Controller Advancements in iOS 8" от WWDC 2014 входит в это более подробно.

обязательно придайте вашему представленному контроллеру вида четкий цвет фона (в противном случае он все равно будет казаться непрозрачным).

есть еще один вариант: прежде чем показывать модальный контроллер, сделайте снимок экрана всего окна. Вставьте захваченное изображение в UIImageView и добавьте представление изображения в представление контроллера, которое вы собираетесь показать. Затем отправить обратно. Вставьте другой вид над видом изображения (черный фон, Альфа 0.7). Покажите свой модальный контроллер, и он выглядит так, как будто он был прозрачным. Просто попробовал его на iPhone 4 под управлением iOS 4.3.1. Как обаяние.

Это довольно старый, но я решил ту же проблему следующим образом: Поскольку мне нужно представить навигационный контроллер в iPhone, добавление подвида не было жизнеспособным решением.

Так что я сделал:

1) Прежде, чем представить контроллер представления, сделать скриншот текущего экрана:

UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, self.view.opaque, 0.0);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * backgroundImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

2) Создайте контроллер вида, который вы хотите представить, и добавьте фон в качестве подвида, отправив его обратно.

UIViewController * presentingVC = [UIViewController new];
UIImageView * backgroundImageOfPreviousScreen = [[UIImageView alloc] initWithImage:backgroundImage];
[presentingVC.view addSubview:backgroundImageOfPreviousScreen];
[presentingVC.view sendSubviewToBack:backgroundImageOfPreviousScreen];

3) Представьте свой взгляд контроллер, но перед этим в новом контроллере представления добавьте прозрачный вид в viewDidLoad (я использовал ILTranslucentView)

-(void)viewDidLoad
{
    [super viewDidLoad];
    ILTranslucentView * translucentView = [[ILTranslucentView alloc] initWithFrame:self.view.frame];
    [self.view addSubview:translucentView];
    [self.view sendSubviewToBack:translucentView];
}

и это все!

Это, кажется, сломано в IOS 8, я использую навигационный контроллер, а контекст, который отображается, - это контекст меню навигации, который в нашем случае является контроллером скользящего меню.

мы используем pod 'TWTSideMenuViewController', ' 0.3 ' еще не проверили, является ли это проблемой с библиотекой или описанным выше методом.

это работает для меня в iOS 8-9:

1-Установите фон вашего контроллера вида с помощью альфа

2 - добавить этот код:

TranslucentViewController *tvc = [[TranslucentViewController alloc] init];
self.providesPresentationContextTransitionStyle = YES;
self.definesPresentationContext = YES;
[tvc setModalPresentationStyle:UIModalPresentationOverCurrentContext];

[self.navigationController presentViewController:tvc animated:YES completion:nil];

Я записал свои выводы об этом в другой вопрос, но суть его заключается в том, что вы должны позвонить modalPresentationStyle = UIModalPresentationCurrentContext на том, что владеет полным экраном в данный момент. В большинстве случаев это то, что является [UIApplication sharedApplication].делегат.окна rootViewController. Это также может быть новый UIViewController, который был представлен с modalPresentationStyle = UIModalPresentationFullScreen.

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

Я знаю, это довольно старый вопрос. Я застрял на этой проблеме, и я смог получить руководство из этой темы. Итак, поставив здесь, как я получил это сработало :). Я использую раскадровку, и у меня есть переход к ViewController, который должен быть представлен. Контроллер вида имеет прозрачный цвет фона. Теперь в инспекторе атрибутов segue я установил презентацию на "над текущим контекстом".И это сработало для меня. Я разрабатываю для iPhone.

Attributes Inspector of the segue

Я создал открытую библиотеку soruce MZFormSheetController представить лист модальной формы на дополнительном UIWindow. Вы можете использовать его для представления прозрачности модального контроллера вида, даже настроить размер представленного контроллера вида.

в моем состоянии у меня есть вид на тот же viewController. Поэтому сделайте новый контроллер вида для проведения UIView. Сделайте это представление прозрачным, установив его альфа-свойство. Затем по щелчку кнопки я написал этот код. Выглядит неплохо.

UIGraphicsBeginImageContext(objAppDelegate.window.frame.size);
    [objAppDelegate.window.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();



    UIViewController *controllerForBlackTransparentView=[[[UIViewController alloc] init] autorelease];
    [controllerForBlackTransparentView setView:viewForProfanity];

    UIImageView *imageForBackgroundView=[[UIImageView alloc] initWithFrame:CGRectMake(0, -20, 320, 480)];
    [imageForBackgroundView setImage:viewImage];

    [viewForProfanity insertSubview:imageForBackgroundView atIndex:0];

    [self.navigationController presentModalViewController:controllerForBlackTransparentView animated:YES];

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

вот категория, которую я создал, которая решит проблему.

    //
    //  UIViewController+Alerts.h
    //

    #import <UIKit/UIKit.h>

    @interface UIViewController (Alerts)

    - (void)presentAlertViewController:(UIViewController *)alertViewController animated:(BOOL)animated;
    - (void)dismissAlertViewControllerAnimated:(BOOL)animated;

    @end


    //
    //  UIViewController+Alerts.m
    //

    #import "UIViewController+Alerts.h"

    @implementation UIViewController (Alerts)

    - (void)presentAlertViewController:(UIViewController *)alertViewController animated:(BOOL)animated
    {
            // Setup frame of alert view we're about to display to just off the bottom of the view
            [alertViewController.view setFrame:CGRectMake(0, self.view.frame.size.height, alertViewController.view.frame.size.width, alertViewController.view.frame.size.height)];

            // Tag this view so we can find it again later to dismiss
            alertViewController.view.tag = 253;

            // Add new view to our view stack
            [self.view addSubview:alertViewController.view];

            // animate into position
            [UIView animateWithDuration:(animated ? 0.5 : 0.0) animations:^{
                    [alertViewController.view setFrame:CGRectMake(0, (self.view.frame.size.height - alertViewController.view.frame.size.height) / 2, alertViewController.view.frame.size.width, alertViewController.view.frame.size.height)];
            }];      
    }

    - (void)dismissAlertViewControllerAnimated:(BOOL)animated
    {
            UIView *alertView = nil;

            // find our tagged view
            for (UIView *tempView in self.view.subviews)
            {
                    if (tempView.tag == 253)
                    {
                            alertView = tempView;
                            break;
                    }
            }

            if (alertView)
            {
                    // clear tag
                    alertView.tag = 0;

                    // animate out of position
                    [UIView animateWithDuration:(animated ? 0.5 : 0.0) animations:^{
                            [alertView setFrame:CGRectMake(0, self.view.frame.size.height, alertView.frame.size.width, alertView.frame.size.height)];
                    }];      
            }
    }

    @end

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

Не могу показать изображение, не хватает репутации)))

вид контейнера, доступный из iOS6.

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

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

но по этому пути вы теряете анимацию "слайд-снизу".

Я нашел это элегантное и простое решение для iOS 7 и выше!

для iOS 8 Apple добавила UIModalPresentationOverCurrentContext, но он не работает для iOS 7 и ранее, поэтому я не мог использовать его для своего случая.

пожалуйста, создайте категорию и поместите следующий код.

.файл H

typedef void(^DismissBlock)(void);

@interface UIViewController (Ext)

- (DismissBlock)presentController:(UIViewController *)controller
              withBackgroundColor:(UIColor *)color
                         andAlpha:(CGFloat)alpha
                presentCompletion:(void(^)(void))presentCompletion;

@end

.файл м

#import "UIViewController+Ext.h"

@implementation UIViewController (Ext)

- (DismissBlock)presentController:(UIViewController *)controller
              withBackgroundColor:(UIColor *)color
                         andAlpha:(CGFloat)alpha
                presentCompletion:(void(^)(void))presentCompletion
{
    controller.modalPresentationStyle = UIModalPresentationCustom;

    UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
    __block UIView *overlay = [[UIView alloc] initWithFrame:keyWindow.bounds];
    if (color == nil) {
        color = [UIColor blackColor];
    }
    overlay.backgroundColor = color;
    overlay.alpha = alpha;

    if (self.navigationController != nil) {
        [self.navigationController.view addSubview:overlay];
    }
    else if (self.tabBarController != nil) {
        [self.tabBarController.view addSubview:overlay];
    }
    else {
        [self.view addSubview:overlay];
    }

    self.modalPresentationStyle = UIModalPresentationCurrentContext;
    [self presentViewController:controller
                       animated:true
                     completion:presentCompletion];

    DismissBlock dismissBlock = ^(void) {
        [self dismissViewControllerAnimated:YES completion:nil];
        [UIView animateWithDuration:0.25
                         animations:^{
                             overlay.alpha = 0;
                         } completion:^(BOOL finished) {
                             [overlay removeFromSuperview];
                         }];
    };
    return dismissBlock;
}

@end

Примечание: он работает также для navigationContoller, tabBarController.

пример использование:

       // Please, insure that your controller has clear background
       ViewController *controller = [ViewController instance];
        __block DismissBlock dismissBlock = [self presentController:controller
                                                withBackgroundColor:[UIColor blackColor]
                                                           andAlpha:0.5
                                                  presentCompletion:nil];
        // Supposed to be your controller's closing callback
        controller.dismissed = ^(void) {
            dismissBlock();
        };

наслаждайтесь! и, пожалуйста, оставьте некоторые отзывы.

после многих исследований похоже, что это решит нашу проблему и послужит нашей цели.

создайте сегмент от исходного VC до конечного VC с идентификатором.

например " goToDestinationViewController" хорошо, чтобы облегчить жизнь давайте рассмотрим текущий контроллер вида, то есть тот, который вы хотите за вашим прозрачным видом в качестве источника и назначения в качестве назначения

теперь в исходном VC в viewDidLoad: или view

performSegueWithIdentifier("goToDestinationViewController", sender: nil)

хорошие мы они уже на полпути. Теперь переходим к раскадровке. Нажмите на кнопку segue. который должен выглядеть так: segue

измените параметры на то, что показано.

теперь приходит реальное решение.

в viewDidLoad контроллера вида назначения добавьте этот код.

self.modalPresentationStyle = .Custom

.........................................................................ТАК ПРОСТО..................................................................

Это лучший и самый чистый способ, который я нашел до сих пор:

@protocol EditLoginDelegate <NSObject>

- (void)dissmissEditLogin;

@end

- (IBAction)showtTransparentView:(id)sender {

    UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"foo bar"
                                                         delegate:self
                                                cancelButtonTitle:@"cancel"
                                           destructiveButtonTitle:@"destructive"
                                                otherButtonTitles:@"ok", nil];

    [actionSheet showInView:self.view];

}

- (void)willPresentActionSheet:(UIActionSheet *)actionSheet{

    UIStoryboard *loginStoryboard     = [UIStoryboard storyboardWithName:@"Login" bundle:nil];
    self.editLoginViewController      = [loginStoryboard instantiateViewControllerWithIdentifier:@"EditLoginViewController"];

    self.editLoginViewController.delegate = self;

    [self.editLoginViewController viewWillAppear:NO];
    [actionSheet addSubview:self.editLoginViewController.view];
    [self.editLoginViewController viewDidAppear:NO];
}

лучшее решение, с которым я столкнулся, - это использовать метод addChildViewController. Вот отличный пример : добавить представление контроллера дочернего вида в подвиде контроллера родительского вида

Я пытаюсь использовать несколько методов для решения, но все равно не удалось, следующий код реализован окончательно.

разрешение от Swift:

// A.swift init method
modalPresentationStyle = .currentContext // or overCurrentContent
modalTransitionStyle = .crossDissolve // dissolve means overlay

затем в контроллере вида B:

// B.swift
let a = A()
self.present(a, animated: true, completion: nil)