ios - swift present modally programmatically
iOS: Modal ViewController con fondo transparente (22)
La pantalla de inicio de sesión es un modal, lo que significa que se encuentra en la parte superior de la pantalla anterior. Hasta ahora tenemos Borrosa de fondo, pero no está borrando nada; es solo un fondo gris.
Necesitamos configurar nuestro Modal apropiadamente.
En primer lugar, debemos cambiar el fondo de View View''s View to Clear color. Simplemente significa que debe ser transparente. Por defecto, esa vista es blanca.
En segundo lugar, debemos seleccionar el Segue que conduce a la pantalla de inicio de sesión, y en el inspector de atributos, establecer la presentación en el contexto actual. Esta opción solo está disponible con Auto Layout y Clases de tamaño habilitadas.
Estoy tratando de presentar un controlador de vista de forma modal, con un fondo transparente. Mi objetivo es permitir que se muestren al mismo tiempo la vista de los controladores de vista presentados y presentados. El problema es que cuando finaliza la animación de presentación, desaparece la vista del controlador de vista de presentación.
- (IBAction)pushModalViewControllerButtonPressed:(id)sender
{
ModalViewController *modalVC = [[ModalViewController alloc] init];
[self presentViewController:modalVC animated:YES completion:nil];
}
Sé que podría agregar la vista como una subvista, pero me gustaría evitar esta solución por alguna razón. ¿Cómo podría solucionarlo?
Agregué estas tres líneas en el método init en el controlador de vista presentado, y funciona como un amuleto:
self.providesPresentationContextTransitionStyle = YES;
self.definesPresentationContext = YES;
[self setModalPresentationStyle:UIModalPresentationOverCurrentContext];
EDITAR (trabajando en iOS 9.3):
self.modalPresentationStyle = UIModalPresentationOverFullScreen;
Según la documentación:
UIModalPresentationOverFullScreen Un estilo de presentación de vista en el que la vista presentada cubre la pantalla. Las vistas debajo del contenido presentado no se eliminan de la jerarquía de vistas cuando finaliza la presentación. Entonces, si el controlador de vista presentado no llena la pantalla con contenido opaco, el contenido subyacente se muestra a través de.
Disponible en iOS 8.0 y posterior.
Cree una transición para presentar modalmente y establezca la propiedad de Presentación de esa transición en el contexto actual, funcionará al 100%
En iOS 8.0 y superior, se puede hacer estableciendo la propiedad modalPresentationStyle en 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];
Es un poco raro, pero para mí este código funciona (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;
}];
}];
Este código funciona también en iPhone
Esta categoría funcionó para mí (ios 7, 8 y 9)
Archivo H
@interface UIViewController (navigation)
- (void) presentTransparentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion;
@end
Archivo 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
Establezca modalPresentationStyle
de navegación en UIModalPresentationCustom
y configura el color de fondo de tu controlador de visualización presentado como color claro.
Este código funciona bien en iPhone con iOS6 e iOS7:
presentedVC.view.backgroundColor = YOUR_COLOR; // can be with ''alpha''
presentingVC.modalPresentationStyle = UIModalPresentationCurrentContext;
[presentingVC presentViewController:presentedVC animated:YES completion:NULL];
En este caso, te pierdes la animación deslizable. Para retener la animación, puede usar la siguiente extensión "no elegante":
[presentingVC presentViewController:presentedVC animated:YES completion:^{
[presentedVC dismissViewControllerAnimated:NO completion:^{
presentingVC.modalPresentationStyle = UIModalPresentationCurrentContext;
[presentingVC presentViewController:presentedVC animated:NO completion:NULL];
}];
}];
Si nuestra presentaciónV está ubicada dentro de UINavigationController o UITabbarController, debe operar con esos controladores como presentandoVC.
Además, en iOS7 puede implementar animación de transición personalizada aplicando el protocolo UIViewControllerTransitioningDelegate
. Por supuesto, en este caso puede obtener un fondo transparente
@interface ModalViewController : UIViewController <UIViewControllerTransitioningDelegate>
En primer lugar, antes de presentar, debe establecer modalPresentationStyle
modalViewController.modalPresentationStyle = UIModalPresentationCustom;
Entonces tienes que implementar dos métodos de protocolo
- (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;
}
Lo último es definir su transición personalizada en la clase 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
}
}
Este código siguiente solo funciona en el iPad.
self.view.backgroundColor = [UIColor clearColor];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:modalVC animated:YES];
Me gustaría agregar una vista secundaria.
Aquí hay una muy buena discusión. Mira los comentarios específicamente. No solo la respuesta.
Si fuera tú, no lo haría. Agregaría una sub-vista y lo haría. Parece que me da un mejor control sobre las cosas.
EDITAR:
Como menciona Paul Linsay, desde iOS 8, todo lo que se necesita es UIModalPresentationOverFullScreen
para el modalPresentationStyle del ViewController que se presenta. Esto también cubriría los botones navigationBar y tabBar.
He creado un objeto para manejar la presentación de lo que llamo un "modal superpuesto", lo que significa que conserva la vista de fondo y le permite tener un modal con un fondo transparente.
Tiene un único método simple que hace esto:
- (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];
}
Es importante establecer la propiedad modalPresentationCapturesStatusBarAppearance
en YES
y forzar la apariencia de la barra de estado para actualizar, si su controlador de vista presentado tiene un preferredStatusBarStyle
diferente.
Este objeto debe tener @property (assign, nonatommic) isPresenting
Desea que este objeto cumpla los protocolos UIViewControllerAnimatedTransitioning
y UIViewControllerTransitioningDelegate
e implemente los siguientes métodos:
- (id)animationControllerForPresentedController:(UIViewController *)presented
presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source
{
self.isPresenting = YES;
return self;
}
- (id)animationControllerForDismissedController:(UIViewController *)dismissed
{
self.isPresenting = NO;
return self;
}
y:
- (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];
}];
}
}
Esto hace una animación de deslizamiento desde el fondo que imita la animación modal predeterminada, pero puede hacerla como quiera.
Lo importante es que la vista del controlador de visualización de presentación permanecerá en la parte posterior, lo que le permitirá crear un efecto transparente.
Esta solución funciona para iOS 7+
La solución a esta respuesta usando swift sería la siguiente.
let vc = MyViewController()
vc.view.backgroundColor = UIColor.clear // or whatever color.
vc.modalPresentationStyle = .overCurrentContent
present(vc, animated: true, completion: nil)
Luché un poco con Interface Builder of XCode 7 para establecer el estilo de presentación como @VenuGopalTewari sugirió. En esta versión, parece que no hay un modo de presentación Over Current Context
o Over Full Screen
para la transición. Por lo tanto, para que funcione, configuré el modo Default
:
Además, establecí el modo de presentación del controlador de vista presentado de forma modal en Over Full Screen
:
Otra forma es usar una "vista de contenedor". Simplemente haz alfa debajo de 1 e incrusta con seque. XCode 5, objetivo iOS7. Probado en iPhone.
Vista de contenedor disponible desde iOS6. Link a la publicación del blog sobre eso.
Para aquellos que intentan hacer que esto funcione en iOS 8, la forma "aprobada por Apple" para mostrar un controlador de vista modal transparente es estableciendo modalPresentationStyle
en el actual controlador ed en UIModalPresentationOverCurrentContext
.
Esto se puede hacer en código o estableciendo las propiedades del segue en el guión gráfico.
De la documentación de UIViewController:
UIModalPresentationOverCurrentContext
Un estilo de presentación donde el contenido se muestra solo sobre el contenido del controlador de vista padre. Las vistas debajo del contenido presentado no se eliminan de la jerarquía de vistas cuando finaliza la presentación. Entonces, si el controlador de vista presentado no llena la pantalla con contenido opaco, el contenido subyacente se muestra a través de.
Al presentar un controlador de vista en un popover, este estilo de presentación solo se admite si el estilo de transición es UIModalTransitionStyleCoverVertical. Intentar utilizar un estilo de transición diferente desencadena una excepción. Sin embargo, puede usar otros estilos de transición (excepto la transición de curvatura parcial) si el controlador de vista principal no está en un popover.
Disponible en iOS 8.0 y posterior.
https://developer.apple.com/documentation/uikit/uiviewcontroller
El video ''Ver mejoras del controlador en iOS 8'' de la WWDC 2014 entra en esto con cierto detalle.
Nota:
- Asegúrese de darle a su controlador de vista presentado un color de fondo claro, ¡para que no sea realmente transparente!
- Tienes que configurar esto antes de presentar, es decir, establecer este parámetro en
viewDidLoad
de the presentedViewController no tendrá ningún efecto
PresentViewController con fondo transparente: en iOS 8 e 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];
Y en MYViewController establece el color de fondo negro y reduce la opacidad
Si está usando Storyboard, puede seguir este paso:
- Agregue un controlador de vista (V2), configure la interfaz de usuario de la manera que desee
- agregue un UIView - configure el fondo en negro y la opacidad en 0.5
- agregue otra UIView (2) - que servirá como su ventana emergente (Pls tenga en cuenta que la UIView y la UIView (2) no deben tener el mismo nivel / jerarquía. No haga que la vista de la imagen sea el niño de la vista; de lo contrario, la opacidad de la uiview afectará a UIView (2))
Presente V2 Modally
Haga clic en el segue. En el inspector de atributos, configure la presentación como en pantalla completa . Eliminar la animación si lo desea
- Seleccione V2. En el inspector de atributos, configure la presentación como en pantalla completa . Verificar define contexto y proporciona contexto
- Seleccione la vista principal de su V2 (por favor, compruebe la imagen). Establecer backgroundColor para borrar el color
Si usa la transición modal, asegúrese de configurarla como esta imagen (puede desactivar la animación si lo desea)
Trabajando para 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)
}
}
Un método completo probado en iOS 7 e 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
Una forma muy simple de hacer esto (usando Storyboards
, por ejemplo) es:
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
}];
Esto presentará un UIViewController
en un Storyboard
modalmente, pero con un trasfondo translúcido.
en appdelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[_window rootViewController]setModalPresentationStyle:UIModalPresentationCurrentContext];
return YES;
}
en la primera vez que ve el controlador desde donde debe cargar la siguiente vista:
NextViewController *customvc = [[NextViewController alloc]init];
[self presentViewController:customvc animated:YES completion:^{
}];
en su próximo ViewController que se agregará transparente:
- (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];
}
Para recapitular todas las buenas respuestas y comentarios aquí y para seguir teniendo una animación mientras me muevo a su nuevo ViewController
esto es lo que hice: (Admite iOS 6 y versiones posteriores)
Si usa UINavigationController
/ UITabBarController
este es el camino a seguir:
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];
Si lo haces, perderás tu animación modalTransitionStyle
. Para resolverlo, puede agregar fácilmente a su clase SomeViewController
esto:
-(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;
}