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