J'essaie de présenter un contrôleur de vue de manière modale, avec un arrière-plan transparent. Mon objectif est de permettre l'affichage simultané de la vue des contrôleurs de présentation présentés et présentés. Le problème est que, lorsque l'animation de présentation est terminée, la vue du contrôleur de vue de présentation disparaît.
- (IBAction)pushModalViewControllerButtonPressed:(id)sender
{
ModalViewController *modalVC = [[ModalViewController alloc] init];
[self presentViewController:modalVC animated:YES completion:nil];
}
Je sais que je pourrais simplement ajouter la vue en tant que sous-vue, mais j'aimerais éviter cette solution pour une raison quelconque. Comment pourrais-je le réparer?
Ce code suivant ne fonctionne que sur l'iPad.
self.view.backgroundColor = [UIColor clearColor];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:modalVC animated:YES];
J'irais avec ajouter une vue secondaire.
Voici une très bonne discussion. Regardez les commentaires en particulier. Pas seulement la réponse.
Si j'étais vous, je ne le ferais pas. Je voudrais ajouter une vue secondaire et le faire. Cela semble me permettre de mieux contrôler les choses.
MODIFIER:
Comme mentionné par Paul Linsay, depuis iOS 8, tout ce qui est nécessaire est UIModalPresentationOverFullScreen
pour le modalPresentationStyle du ViewController présenté. Cela couvrirait également les boutons navigationBar et tabBar.
Pour ceux qui essaient de faire fonctionner cela dans iOS 8, la méthode "approuvée par Apple" pour afficher un contrôleur de vue modale transparent consiste à définir modalPresentationStyle
sur le contrôleur presented sur UIModalPresentationOverCurrentContext
.
Cela peut être fait en code ou en définissant les propriétés de la séquence dans le storyboard.
A partir de la documentation UIViewController:
UIModalPresentationOverCurrentContext
Un style de présentation où le contenu est affiché uniquement sur le contenu du contrôleur de vue parent. Les vues sous le présenté les contenus ne sont pas supprimés de la hiérarchie des vues lors de la présentation se termine. Donc, si le contrôleur de vue présenté ne remplit pas l'écran avec un contenu opaque, le contenu sous-jacent est visible.
Lors de la présentation d’un contrôleur de vue dans un popover, cette présentation Le style n'est pris en charge que si le style de transition est UIModalTransitionStyleCoverVertical. Tenter d'utiliser un autre Le style de transition déclenche une exception. Cependant, vous pouvez utiliser d'autres styles de transition (sauf la transition curl partielle) si le parent contrôleur de vue n'est pas dans un popover.
Disponible dans iOS 8.0 et versions ultérieures.
https://developer.Apple.com/documentation/uikit/uiviewcontroller
La vidéo «View Controller Advancements in iOS 8» de WWDC 2014 va plus en détail.
Remarque:
viewDidLoad
du PresentViewController n'aura aucun effet.Dans iOS 8.0 et versions ultérieures, vous pouvez définir la propriété 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];
Ce code fonctionne bien sur iPhone sous iOS6 et iOS7:
presentedVC.view.backgroundColor = YOUR_COLOR; // can be with 'alpha'
presentingVC.modalPresentationStyle = UIModalPresentationCurrentContext;
[presentingVC presentViewController:presentedVC animated:YES completion:NULL];
Dans ce cas, vous manquez l'animation par diapositives. Pour conserver l'animation, vous pouvez toujours utiliser l'extension "non élégante" suivante:
[presentingVC presentViewController:presentedVC animated:YES completion:^{
[presentedVC dismissViewControllerAnimated:NO completion:^{
presentingVC.modalPresentationStyle = UIModalPresentationCurrentContext;
[presentingVC presentViewController:presentedVC animated:NO completion:NULL];
}];
}];
Si notre presentV est situé dans UINavigationController ou UITabbarController, vous devez utiliser ces contrôleurs en tant que presentationVC.
De plus, dans iOS7, vous pouvez implémenter une animation de transition personnalisée en appliquant le protocole UIViewControllerTransitioningDelegate
. Bien sûr, dans ce cas, vous pouvez obtenir un fond transparent
@interface ModalViewController : UIViewController <UIViewControllerTransitioningDelegate>
Tout d'abord, avant de présenter, vous devez définir modalPresentationStyle
modalViewController.modalPresentationStyle = UIModalPresentationCustom;
Ensuite, vous devez implémenter deux méthodes de protocole
- (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;
}
La dernière chose à faire est de définir votre transition personnalisée dans la classe 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
}
}
J'ai eu un peu de mal avec Interface Builder de XCode 7 pour définir le style de présentation comme suggéré par @VenuGopalTewari. Dans cette version, il semble n'y avoir aucun mode de présentation Over Current Context
ou Over Full Screen
pour le segue. Ainsi, pour que cela fonctionne, je règle le mode sur Default
:
De plus, je règle le mode de présentation du contrôleur de vue à présentation modale sur Over Full Screen
:
Créez une séquence pour une présentation modale et définissez la propriété Presentation de cette séquence sur le contexte actuelit fonctionnera à 100%
PresentViewController avec fond transparent - sous iOS 8 et 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];
Et dans MYViewController, définissez la couleur de fond noire et réduisez l'opacité
C'est un peu hacky, mais pour moi ce code fonctionne (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;
}];
}];
Ce code fonctionne aussi sur iPhone
Cette catégorie a fonctionné pour moi (iOS 7, 8 et 9)
Fichier H
@interface UIViewController (navigation)
- (void) presentTransparentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion;
@end
Fichier 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
Si vous utilisez Storyboard, vous pouvez suivre cette étape:
- Ajoutez un contrôleur de vue (V2), configurez l'interface utilisateur comme vous le souhaitez
Present V2 Modally
Cliquez sur la segue. Dans l'inspecteur Attributs, définissez la présentation comme en plein écran . Supprimer l'animation si vous aimez
- Sélectionnez V2. Dans l'inspecteur Attributs, définissez la présentation comme en plein écran . Vérifier Définit le contexte et fournit le contexte
- Sélectionnez le MainView de votre V2 (image de contrôle Pls.). Définissez backgroundColor sur Clear Color
J'ai ajouté ces trois lignes dans la méthode init dans le contrôleur de vue présenté, et fonctionne comme un charme:
self.providesPresentationContextTransitionStyle = YES;
self.definesPresentationContext = YES;
[self setModalPresentationStyle:UIModalPresentationOverCurrentContext];
EDIT (fonctionne sur iOS 9.3):
self.modalPresentationStyle = UIModalPresentationOverFullScreen;
Selon la documentation:
UIModalPresentationOverFullScreen Style de présentation de vue dans lequel la vue présentée couvre l'écran. Les vues sous le contenu présenté ne sont pas supprimées de la hiérarchie des vues lorsque la présentation est terminée. Ainsi, si le contrôleur de vue présenté ne remplit pas l'écran de contenu opaque, le contenu sous-jacent est visible.
Disponible dans iOS 8.0 et versions ultérieures.
Une autre méthode consiste à utiliser une "vue conteneur". Il suffit de faire alpha en dessous de 1 et intégrer avec seque. XCode 5, cible iOS7. Testé sur iPhone.
Vue du conteneur disponible sur iOS6 . Lien pour publier un article à ce sujet.
La solution à cette réponse en utilisant Swift serait la suivante.
let vc = MyViewController()
vc.view.backgroundColor = UIColor.clear // or whatever color.
vc.modalPresentationStyle = .overCurrentContent
present(vc, animated: true, completion: nil)
J'ai créé un objet pour gérer la présentation de ce que j'appelle un "modal superposé", ce qui signifie qu'il conserve la vue de l'arrière-plan et vous permet d'avoir un modal avec un arrière-plan transparent.
Il a une seule méthode simple qui fait ceci:
- (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];
}
Il est important de définir la propriété modalPresentationCapturesStatusBarAppearance
sur YES
et de forcer la mise à jour de l'apparence de la barre d'état, si le contrôleur de vue que vous présentez possède une variable preferredStatusBarStyle
différente.
Cet objet devrait avoir un @property (assign, nonatommic) isPresenting
Vous souhaitez que cet objet respecte les protocoles UIViewControllerAnimatedTransitioning
et UIViewControllerTransitioningDelegate
et implémente les méthodes suivantes:
- (id)animationControllerForPresentedController:(UIViewController *)presented
presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source
{
self.isPresenting = YES;
return self;
}
- (id)animationControllerForDismissedController:(UIViewController *)dismissed
{
self.isPresenting = NO;
return self;
}
et:
- (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];
}];
}
}
Cela fait une animation glissée à partir du bas imitant l'animation modale par défaut, mais vous pouvez en faire ce que vous voulez.
L'important est que la vue du contrôleur de la vue de présentation reste à l'arrière, ce qui vous permet de créer un effet transparent.
Cette solution fonctionne pour iOS 7+
Un moyen très simple de faire cela (en utilisant Storyboards
, par exemple) est:
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
}];
Ceci présentera une UIViewController
dans une Storyboard
modale, mais avec un arrière-plan translucide.
Travailler pour 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)
}
}
Pour récapituler toutes les bonnes réponses et commentaires ici et pour avoir une animation tout en déplaçant votre nouvelle ViewController
c'est ce que j'ai fait: (Prise en charge de iOS 6 et plus)
Si vous utilisez une UINavigationController
\UITabBarController
c'est la voie à suivre:
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 vous le faites, vous perdrez votre animation modalTransitionStyle
. Pour le résoudre, vous pouvez facilement ajouter à votre classe SomeViewController
ceci:
-(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;
}
Swift 4.2
guard let someVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "someVC") as? someVC else {
return
}
someVC.modalPresentationStyle = .overCurrentContext
present(someVC, animated: true, completion: nil)
Si vous utilisez le mode modal, assurez-vous de le définir comme cette image (vous pouvez désactiver l'animation si vous le souhaitez).
Bien sûr, vous devez définir UIModalPresentationCurrentContext, mais l'emplacement pour définir clearColor est également très important! Vous ne pouvez pas définir d'arrière-plan dans la fonction viewDidLoad, définissez-le avant le chargement de la vue, comme dans le contrôleur de vue root ou dans la fonction init du contrôleur à afficher!
actionController.view.backgroundColor = [UIColor clearColor];
[self presentViewController:actionController animated:YES completion:nil];
ou
- (instancetype)init {
self = [super initWithNibName:nil bundle:nil];
if(self) {
self.modalPresentationStyle = UIModalPresentationOverCurrentContext;
[self.view setBackgroundColor:[UIColor clearColor]];
}
return self;
}
Une méthode complète testée sur iOS 7 et 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
Définissez la modalPresentationStyle
de la navigation sur UIModalPresentationCustom
et définissez la couleur d'arrière-plan de votre contrôleur de vue présenté en tant que couleur claire.
dans appdelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[_window rootViewController]setModalPresentationStyle:UIModalPresentationCurrentContext];
return YES;
}
dans votre vue d’abord, le contrôleur à partir duquel vous devez charger la vue suivante:
NextViewController *customvc = [[NextViewController alloc]init];
[self presentViewController:customvc animated:YES completion:^{
}];
dans votre nextViewController qui doit être ajouté de manière 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];
}
L'écran de connexion est un modal, ce qui signifie qu'il se trouve en haut de l'écran précédent. Jusqu’à présent, nous avons un arrière-plan flou, mais il n’a rien de flou; c'est juste un fond gris.
Tout d’abord, nous devons modifier l’arrière-plan View Controller de View Controller en Clear color. Cela signifie simplement que cela devrait être transparent. Par défaut, cette vue est blanche.
Deuxièmement, nous devons sélectionner la Segue qui mène à l'écran de connexion et, dans l'inspecteur d'attributs, définir la présentation sur le contexte actuel. Cette option est uniquement disponible lorsque la disposition automatique et les classes de taille sont activées.