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];
Я бы пошел с добавлением подвида.
вот очень хорошая дискуссия. Посмотрите на комментарии конкретно. Не только ответ.
на твоем месте я бы этого не делал. Я бы добавил дополнительный вид и сделал это. Кажется, это дает мне лучший контроль над вещами.
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];
этот код отлично работает на 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 %
Я немного боролся с построителем интерфейса XCode 7, чтобы установить стиль презентации, как предложил @VenuGopalTewari. В этой версии, кажется, нет
Over Current Context
илиOver Full Screen
режим презентации для segue. Таким образом, чтобы заставить его работать, я установил режимDefault
:дополнительно я установил режим представления модально представленного контроллера вида
Over Full Screen
:
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.
вид контейнера, доступный из iOS6. ссылке чтобы написать об этом в блоге.
Если вы используете раскадровку, вы можете выполнить этот шаг:
- добавить контроллер вида (V2), настроить пользовательский интерфейс так, как вы хотите его
- добавить UIView-установить фон на черный и непрозрачность до 0,5
- добавьте еще один UIView (2) - который будет служить вашим всплывающим окном(обратите внимание, что UIView и UIView (2) не должны иметь одинаковый уровень/иерархию. Не делайте imageview дочерним видом в противном случае непрозрачность uiview повлияет на UIView (2))
Присутствует V2 Модально
Нажмите кнопку segue. В инспекторе атрибутов задайте представление как В Течение Полного Экрана. Удалить анимацию, если вам нравится
- Выберите V2. В инспекторе атрибутов задайте представление как В Течение Полного Экрана. Проверьте определяет контекст и Предоставляет Контекст
- выберите MainView вашего V2 (Pls. Проверьте изображение). Установить фон для Ясный Цвет
Я создал объект для обработки представления того, что я называю "наложенным модальным", то есть он сохраняет вид фона и позволяет вам иметь модальный с прозрачным фоном.
он имеет один простой метод, который делает это:
- (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)
Если вы используете модальный сегмент, убедитесь, что он установлен как это изображение (вы можете отключить анимацию, если хотите)
полный метод, протестированный на 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.