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

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

[self presentModalViewController:controller animated:YES];

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

Есть ли способ сохранить прозрачность?

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

Ответ 1

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

Ответ 2

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

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

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

Ответ 3

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

self.window.rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;

Ответ 4

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

// 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 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];    
}

Ответ 5

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

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

UIModalPresentationOverCurrentContext

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

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

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

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

Видеоролик "Просмотр контроллеров в iOS 8" от WWDC 2014 подробно рассматривается в этой статье.

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

Ответ 6

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

Ответ 7

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

Итак, что я сделал:

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

И это все!

Ответ 8

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

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

Ответ 9

Это со мной работало в 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];

Ответ 10

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

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

Ответ 11

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

Ответ 12

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

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

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

Ответ 13

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

Ответ 14

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

    //
    //  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

Ответ 15

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

не может показывать изображение, недостаточно репутации)))

Просмотр контейнера из iOS6.

Ответ 16

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

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

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

Ответ 17

Я нашел это элегантное и простое решение для 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

.m file

#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 closing callback
        controller.dismissed = ^(void) {
            dismissBlock();
        };

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

Ответ 18

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

создать segue от источника VC до целевого VC с идентификатором.

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

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

performSegueWithIdentifier("goToDestinationViewController", sender: nil)

Хорошо, мы на полпути. Теперь иди в свою раскадровку. Нажмите на сегмент. который должен выглядеть следующим образом: segue

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

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

в вашем диспетчерском представлении viewDidLoad добавьте этот код.

self.modalPresentationStyle = .Custom

.........................................................................ЭТО ПРОСТО..................................................................

Ответ 19

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

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

Ответ 21

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

Резолюция Свифта:

// 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)