簡體   English   中英

iOS:具有透明背景的Modal ViewController

[英]iOS: Modal ViewController with transparent background

我試圖以模糊方式呈現視圖控制器,具有透明背景。 我的目標是讓呈現和呈現的視圖控制器視圖同時顯示。 問題是,當呈現動畫結束時,呈現視圖控制器的視圖消失。

- (IBAction)pushModalViewControllerButtonPressed:(id)sender
{
    ModalViewController *modalVC = [[ModalViewController alloc] init];
    [self presentViewController:modalVC animated:YES completion:nil];
}

我知道我可以將視圖添加為子視圖,但出於某種原因我想避免使用此解決方案。 我該怎么辦呢?

對於那些試圖讓這個在iOS 8的工作,“蘋果批准”的方式來顯示一個透明的模態視圖控制器是通過設置modalPresentationStyle 控制器上 UIModalPresentationOverCurrentContext

這可以在代碼中完成,也可以通過在故事板中設置segue的屬性來完成。

從UIViewController文檔:

UIModalPresentationOverCurrentContext

一種演示樣式,其中內容僅顯示在父視圖控制器的內容上。 演示文稿完成后,不會從視圖層次結構中刪除所顯示內容下方的視圖。 因此,如果呈現的視圖控制器沒有用不透明的內容填充屏幕,則底層內容會顯示出來。

在彈出框中顯示視圖控制器時,僅當過渡樣式為UIModalTransitionStyleCoverVertical時才支持此演示樣式。 嘗試使用不同的過渡樣式會觸發異常。 但是,如果父視圖控制器不在彈出框中,則可以使用其他過渡樣式(部分卷曲過渡除外)。

適用於iOS 8.0及更高版本。

https://developer.apple.com/documentation/uikit/uiviewcontroller

來自WWDC 2014的“在iOS 8中查看控制器進展”視頻詳細介紹了這一點。

注意:

  • 務必為您呈現的視圖控制器提供清晰的背景顏色,以免它實際上是透明的!
  • 你必須呈現之前設置它即在viewDidLoad中設置此參數不會有任何影響

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

請參見圖像附加

以下代碼僅適用於iPad。

self.view.backgroundColor = [UIColor clearColor];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:modalVC animated:YES];

我會添加一個子視圖。

這是一個非常好的討論。 具體看一下評論。 不僅是答案。

模態視圖

如果我是你,我就不會這樣做。 我會添加一個子視圖並執行它。 它似乎讓我更好地控制事物。

編輯:

正如Paul Linsay所提到的,因為iOS 8所需要的只是UIModalPresentationOverFullScreen用於呈現ViewController的modalPresentationStyle。 這也包括navigationBar和tabBar按鈕。

此代碼在iOS6和iOS7下的iPhone上運行正常:

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

如果我們的presentationV位於UINavigationController或UITabbarController內部,則需要使用該控制器作為presentationVC進行操作。

此外,在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
    }
}

我使用XCode 7的Interface Builder稍微努力將Presentation Style設置為@VenuGopalTewari建議。 在這個版本中,似乎沒有針對segue的Over Current ContextOver Full Screen演示模式。 因此,為了使其工作,我將模式設置為Default

在此輸入圖像描述 在此輸入圖像描述

另外,我將模態呈現的視圖控制器的演示模式設置為Over Full Screen

在此輸入圖像描述

創建一個segue以模態呈現並將該segue的Presentation屬性設置為當前上下文它將100%工作

在此輸入圖像描述

具有透明背景的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中設置背景顏色為黑色並降低不透明度

這有點hacky方式,但對我來說這個代碼有效(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

如果您使用的是Storyboard,則可以按照以下步驟操作:

  1. 添加視圖控制器(V2),按照您希望的方式設置UI
  • 添加UIView - 將背景設置為黑色,將不透明度設置為0.5
  • 添加另一個UIView(2) - 將作為你的彈出窗口(請注意UIView和UIView(2)必須具有相同的級別/層次結構。不要使imageview成為視圖的子級別,否則uiview的不透明度將影響UIView(2))
  1. 禮物V2模態

  2. 單擊segue。 在“屬性”檢查器中,將“演示文稿”設置為“全屏幕” 如果你願意,刪除動畫

故事板

  1. 選擇V2。 在“屬性”檢查器中,將“演示文稿”設置為“全屏幕” 檢查定義上下文並提供上下文

故事板

  1. 選擇V2的MainView(請檢查圖像)。 將backgroundColor設置為Clear Color

故事板

我在呈現的視圖控制器中的init方法中添加了這三行,並且像魅力一樣工作:

self.providesPresentationContextTransitionStyle = YES;
self.definesPresentationContext = YES;
[self setModalPresentationStyle:UIModalPresentationOverCurrentContext];

編輯(在iOS 9.3上工作):

self.modalPresentationStyle = UIModalPresentationOverFullScreen;

根據文件:

UIModalPresentationOverFullScreen一種視圖演示樣式,其中呈現的視圖覆蓋屏幕。 演示文稿完成后,不會從視圖層次結構中刪除所顯示內容下方的視圖。 因此,如果呈現的視圖控制器沒有用不透明的內容填充屏幕,則底層內容會顯示出來。

適用於iOS 8.0及更高版本。

使用swift解決這個問題的方法如下。

let vc = MyViewController()
vc.view.backgroundColor = UIColor.clear // or whatever color.
vc.modalPresentationStyle = .overCurrentContent
present(vc, animated: true, completion: nil)

替代方法是使用“容器視圖”。 只需將alpha設置為低於1並嵌入seque。 XCode 5,目標是iOS7。 在iPhone上測試過。

在此輸入圖像描述

容器視圖可從iOS6獲得。 鏈接到博客文章。

我創建了一個對象來處理我稱之為“疊加模態”的表示,這意味着它保留了背景的視圖,並允許您擁有一個透明背景的模態。

它有一個簡單的方法可以做到這一點:

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

如果您呈現的視圖控制器具有不同的preferredStatusBarStyle ,則將modalPresentationCapturesStatusBarAppearance屬性設置為YES並強制狀態欄外觀更新非常重要。

該對象應具有@property (assign, nonatommic) isPresenting

您希望此對象符合UIViewControllerAnimatedTransitioningUIViewControllerTransitioningDelegate協議並實現以下方法:

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

這將以模態方式在Storyboard呈現UIViewController ,但具有半透明背景。

適用於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)
    }
}

要在這里回顧所有好的答案和評論,並在移動到新的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;
}

當然你應該設置UIModalPresentationCurrentContext,但設置clearColor的地方也很重要! 你不能在viewDidLoad函數中設置背景,在視圖加載之前設置它,就像在根視圖控制器中或在將要出現的控制器的init函數中一樣!

actionController.view.backgroundColor = [UIColor clearColor];
[self presentViewController:actionController animated:YES completion:nil];

要么

- (instancetype)init {

    self = [super initWithNibName:nil bundle:nil];

    if(self) {
        self.modalPresentationStyle = UIModalPresentationOverCurrentContext;
        [self.view setBackgroundColor:[UIColor clearColor]];
    }

    return self;
}

如果您使用模態segue,請確保將其設置為此圖像(如果需要,可以關閉動畫) 在此輸入圖像描述

在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

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)

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

“登錄”屏幕是一個模態,表示它位於上一個屏幕的頂部。 到目前為止,我們有模糊背景,但它並沒有模糊任何東西; 它只是一個灰色的背景。

我們需要正確設置我們的模態。

圖像鏈接目標

  • 首先,我們需要將View Controller的View背景更改為Clear color。 它只是意味着它應該是透明的。 默認情況下,該視圖為白色。

  • 其次,我們需要選擇通向Login屏幕的Segue,並在Attribute Inspector中將Presentation設置為Over Current Context。 此選項僅在啟用自動布局和大小類時可用。

圖像鏈接目標

將導航的modalPresentationStyle設置為UIModalPresentationCustom

並將您呈現的視圖控制器的背景顏色設置為清晰的顏色。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM