presentModalViewControllerを使用して透明なビューを作成する方法


80

モーダルビューを表示しています

[self presentModalViewController:controller animated:YES];

ビューが画面を上に移動すると、ビューが作成されたxibファイルの設定に従って透明になりますが、画面がいっぱいになると不透明になります。

ビューを透明に保つ方法はありますか?

モーダルビューが不透明になっているのではなく、配置されているビューがレンダリングされていないのではないかと思います。


1
この質問は今ではかなり古いものです。答えを探すときは、使用しているiOSのバージョンに当てはまるものを探してください。
Darryl Braaten 2014

このstackoverflow.com/q/27598846/1603234は私を笑顔にします、今あなたの番です:)
Hemang 2014

使用できますviewcontroller.modalPresentationStyle = .FormSheet
ジェラルド

回答:


63

ビューは引き続き透過的ですが、モーダルコントローラーがスタックの最上位に配置されると、その背後のビューは非表示になります(最上位のビューコントローラーの場合と同様)。解決策は、ビューを自分で手動でアニメーション化することです。その場合、behind-viewControllerは非表示になりません(「左」になっていないため)。


おかげで、それは私が疑ったことを確認します。
Darryl Braaten

1
この問題についてAppleにバグレポートを提出しました。オープンレーダー:openradar.appspot.com/radar?id
理論

4
これに関する問題は、提示されたビューが独自の自動回転設定を持つことができないことです。
シザム2013

85

iOS 3.2以降、「トリック」なしでこれを行う方法があります。modalPresentationStyleプロパティのドキュメントを参照してください。viewControllerを表示するrootViewControllerがあります。成功するためのコードは次のとおりです。

viewController.view.backgroundColor = [UIColor clearColor];
rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
[rootViewController presentModalViewController:viewController animated:YES];

このメソッドを使用すると、viewControllerの背景が透明になり、基になるrootViewControllerが表示されます。これはiPadでのみ機能するようです。以下のコメントを参照してください。


1
こんにちは..私の側から+ 1bcozそれはiOS4とiPadでうまく動作します。しかし、iPhone3.0でどのように機能するか。ありがとう
Mitesh Khatri

3
私(iOS 5.0)では機能しません。誰かがコードを表示できますか?
ダニエル

6
これはiPhone / iPodでは機能しないようです。iPadでのみ機能します(回答にリンクされているドキュメントを参照してください)。@simpleBob:多分これがあなたのために働いていない理由ですか?
Mac

1
FYI:私はこの記事では同じ質問尋ねてきた:stackoverflow.com/questions/14419395/...を
クレイジーチンパンジー

1
iOS 8でテストしましたがOver Current Context、プレゼンテーションスタイルとして使用する必要があります。
haxpor 2015

48

これを機能させるために必要なもの:

self.window.rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;

1
簡単に動作します。コードをそのままにしておいたおかげです-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions method and
voila

2
modalPresentationStyle(ウィンドウのではなく)表示しているViewControllerにを設定することもできますrootViewController
mbinna 2013年

ありがとう![self performSegueWithIdentifier:@ "open" sender:self];
DogCoffee 2013年

モーダルのviewdidloadでは、いつでも手動でビューをアニメーション化できます。
ジェイコブK

2
T氏が以下に述べたように、モーダルプレゼンテーションスタイルは、現在フルスクリーンになっているビューコントローラで設定する必要があることに注意してください。
jessepinho 2013年

24

コードを見たい人のために、透明なビューのコントローラーに追加したものを次に示します。

// Add this view to superview, and slide it in from the bottom
- (void)presentWithSuperview:(UIView *)superview {
    // Set initial location at bottom of superview
    CGRect frame = self.view.frame;
    frame.origin = CGPointMake(0.0, superview.bounds.size.height);
    self.view.frame = frame;
    [superview addSubview:self.view];            

    // Animate to new location
    [UIView beginAnimations:@"presentWithSuperview" context:nil];
    frame.origin = CGPointZero;
    self.view.frame = frame;
    [UIView commitAnimations];
}

// Method called when removeFromSuperviewWithAnimation's animation completes
- (void)animationDidStop:(NSString *)animationID
                finished:(NSNumber *)finished
                 context:(void *)context {
    if ([animationID isEqualToString:@"removeFromSuperviewWithAnimation"]) {
        [self.view removeFromSuperview];
    }
}

// Slide this view to bottom of superview, then remove from superview
- (void)removeFromSuperviewWithAnimation {
    [UIView beginAnimations:@"removeFromSuperviewWithAnimation" context:nil];

    // Set delegate and selector to remove from superview when animation completes
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];

    // Move this view to bottom of superview
    CGRect frame = self.view.frame;
    frame.origin = CGPointMake(0.0, self.view.superview.bounds.size.height);
    self.view.frame = frame;

    [UIView commitAnimations];    
}

このソリューションで私が抱えている唯一の問題は、メモリ管理です。例:TestViewController * testView = [[TestViewController alloc] initWithNibName:@ "TestView" bundle:nil]; [testView presentWithSuperview:self.navigationController.view]; ビューは正常に動作しますが、ビューを解放または自動解放しようとすると、そのビュー内のメソッドを呼び出すと、アクセス不良の例外が発生します
Mick Walker

本気ですか?ビューは[superviewaddSubview:]によって保持されると思うので、解放できるはずです。
クリストファージョンソン2010

presentWithSuperviewを呼び出してから、testViewを解放すると、クラッシュします。また、NavigationControllerツールバーなどの「下」に表示されます。–
Ryan Booker

これは私にとって長い間うまく機能していましたが、ランドスケープモードでは機能しなくなりました。誰かがこれと同じ問題を抱えていますか?
Jeffry van de Vuurst 2015年

19

iOS 8でこれを行うためのApple承認の方法は、modalPresentationStyleを「UIModalPresentationOverCurrentContext」に設定することです。

UIViewControllerのドキュメントから:

UIModalPresentationOverCurrentContext

親ViewControllerのコンテンツのみにコンテンツが表示される表示スタイル。提示されたコンテンツの下のビューは、提示が終了してもビュー階層から削除されません。したがって、提示されたView Controllerが不透明なコンテンツで画面を埋めない場合、基になるコンテンツが透けて見えます。

ポップオーバーでViewControllerを表示する場合、この表示スタイルは、遷移スタイルがUIModalTransitionStyleCoverVerticalである場合にのみサポートされます。別の遷移スタイルを使用しようとすると、例外がトリガーされます。ただし、親ビューコントローラがポップオーバーにない場合は、他の遷移スタイル(部分的なカール遷移を除く)を使用できます。

iOS8.0以降で利用できます。

https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/

WWDC2014の「iOS8でのコントローラーの進歩の表示」ビデオでこれについて詳しく説明します。

提示されたビューコントローラに明確な背景色を与えるようにしてください(そうしないと、不透明に見えます)。


iOS8とiOS9で黒い画面が表示されます
Amit Hooda 2015年

実際には、View Controllerのビューの背景色を1未満のアルファ値に設定すると機能します
Pierre

16

別のオプションがあります。モーダルコントローラーを表示する前に、ウィンドウ全体のスクリーンショットをキャプチャします。キャプチャした画像をUIImageViewに挿入し、表示しようとしているコントローラのビューに画像ビューを追加します。その後、送り返します。画像ビューの上に別のビューを挿入します(背景は黒、アルファ0.7)。モーダルコントローラーを表示すると、透明に見えます。iOS4.3.1を実行しているiPhone4で試してみました。魅力のように。


良いもの、私はこれを実装しますそれは私にとって素晴らしかったです。この概念に従う私のコードを追加してください。
Ishu 2011

簡単になるとは誰も言わなかった!:-)
Krumelur 2011

このアプローチでデバイスの回転をどのようにサポートしますか?
カイルクレッグ2012

10

これはかなり古いですが、私は次のように同じ問題を解決しました:iPhoneでナビゲーションコントローラーを提示する必要があるため、サブビューを追加することは実行可能な解決策ではありませんでした。

だから私がしたこと:

1)View Controllerを表示する前に、現在の画面のスクリーンショットを撮ります。

UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, self.view.opaque, 0.0);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * backgroundImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

2)表示するビューコントローラを作成し、背景をサブビューとして追加して、バックに送信します。

UIViewController * presentingVC = [UIViewController new];
UIImageView * backgroundImageOfPreviousScreen = [[UIImageView alloc] initWithImage:backgroundImage];
[presentingVC.view addSubview:backgroundImageOfPreviousScreen];
[presentingVC.view sendSubviewToBack:backgroundImageOfPreviousScreen];

3)View Controllerを提示しますが、その前に新しいView Controllerで、viewDidLoadに透過ビューを追加します(私はILTranslucentViewを使用しました)

-(void)viewDidLoad
{
    [super viewDidLoad];
    ILTranslucentView * translucentView = [[ILTranslucentView alloc] initWithFrame:self.view.frame];
    [self.view addSubview:translucentView];
    [self.view sendSubviewToBack:translucentView];
}

そしてそれがすべてです!


驚くばかり。スクリーンショットが消える原因となった半透明のビューのほかに、すべてがうまく機能しました。
Michal Shatz 2014

これは素晴らしい解決策です!ポップアップのコントローラーコードを親ビューコントローラーとは別に保持することをお勧めします。
1kmonkies 2014年

私にとっては働いていましたが、背景の設定を表示する必要がありましたWillAppear
Leszek

5

これについての私の発見を別の質問に書き留めましたが、その要点はmodalPresentationStyle = UIModalPresentationCurrentContext、現時点で全画面を所有しているものは何でも呼び出す必要があるということです。ほとんどの場合、それは[UIApplication sharedApplication] .delegate.windowのrootViewControllerです。また、で提示された新しいUIViewControllerである可能性もありますmodalPresentationStyle = UIModalPresentationFullScreen

私がこの問題を具体的にどのように解決したのか疑問に思っている場合は、他のはるかに詳細な投稿を読んでください。幸運を!


5

これはIOS8で壊れているようです。私はナビゲーションコントローラを使用しており、表示されているコンテキストはナビゲーションメニューコンテキストであり、この場合はスライディングメニューコントローラです。

ポッド「TWTSideMenuViewController」を使用していますが、「0.3」は、これがまだライブラリまたは上記のメソッドの問題であるかどうかを確認していません。


5

これはiOS8-9で私に働きました:

1-ビューコントローラーの背景をアルファで設定します

2-このコードを追加します:

TranslucentViewController *tvc = [[TranslucentViewController alloc] init];
self.providesPresentationContextTransitionStyle = YES;
self.definesPresentationContext = YES;
[tvc setModalPresentationStyle:UIModalPresentationOverCurrentContext];

[self.navigationController presentViewController:tvc animated:YES completion:nil];

4

私はこれがかなり古い質問であることを知っています。私はこの問題で立ち往生していて、このスレッドからリードを得ることができました。だからここに私がそれをどのように機能させたかを置く:)。私はストーリーボードを使用していて、提示されるViewControllerにセグエを持っています。ビューコントローラの背景色は透明です。セグエの属性インスペクターで、プレゼンテーションを「過電流コンテキスト」に設定しました。これでうまくいきました。私はiPhone用に開発しています。

セグエの属性インスペクター


おかげで、UIModalPresentationStyle.OverCurrentContextをプログラムで設定することによっても機能します
guoleii 2016年

3

追加のUIWindowにモーダルフォームシートを表示するために、オープンソースライブラリMZFormSheetControllerを作成しました。これを使用して、透明度モーダルビューコントローラーを表示したり、表示されたビューコントローラーのサイズを調整したりすることもできます。


使い方を教えてください。コードを呼び出そうとすると、SIGABRTが発生するためです。
マトロソフアレクサンダー2014

3

私の状態では、同じviewControllerでビューを持っています。したがって、UIViewを保持するための新しいViewControllerを作成します。alphaプロパティを設定して、そのビューを透明にします。次に、ボタンをクリックして、このコードを作成しました。よさそうだ。

UIGraphicsBeginImageContext(objAppDelegate.window.frame.size);
    [objAppDelegate.window.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();



    UIViewController *controllerForBlackTransparentView=[[[UIViewController alloc] init] autorelease];
    [controllerForBlackTransparentView setView:viewForProfanity];

    UIImageView *imageForBackgroundView=[[UIImageView alloc] initWithFrame:CGRectMake(0, -20, 320, 480)];
    [imageForBackgroundView setImage:viewImage];

    [viewForProfanity insertSubview:imageForBackgroundView atIndex:0];

    [self.navigationController presentModalViewController:controllerForBlackTransparentView animated:YES];

そしてそれは私が欲しいものを示しています。それが誰かを助けることを願っています。


2

これが私が作成した問題を解決するカテゴリーです。

    //
    //  UIViewController+Alerts.h
    //

    #import <UIKit/UIKit.h>

    @interface UIViewController (Alerts)

    - (void)presentAlertViewController:(UIViewController *)alertViewController animated:(BOOL)animated;
    - (void)dismissAlertViewControllerAnimated:(BOOL)animated;

    @end


    //
    //  UIViewController+Alerts.m
    //

    #import "UIViewController+Alerts.h"

    @implementation UIViewController (Alerts)

    - (void)presentAlertViewController:(UIViewController *)alertViewController animated:(BOOL)animated
    {
            // Setup frame of alert view we're about to display to just off the bottom of the view
            [alertViewController.view setFrame:CGRectMake(0, self.view.frame.size.height, alertViewController.view.frame.size.width, alertViewController.view.frame.size.height)];

            // Tag this view so we can find it again later to dismiss
            alertViewController.view.tag = 253;

            // Add new view to our view stack
            [self.view addSubview:alertViewController.view];

            // animate into position
            [UIView animateWithDuration:(animated ? 0.5 : 0.0) animations:^{
                    [alertViewController.view setFrame:CGRectMake(0, (self.view.frame.size.height - alertViewController.view.frame.size.height) / 2, alertViewController.view.frame.size.width, alertViewController.view.frame.size.height)];
            }];      
    }

    - (void)dismissAlertViewControllerAnimated:(BOOL)animated
    {
            UIView *alertView = nil;

            // find our tagged view
            for (UIView *tempView in self.view.subviews)
            {
                    if (tempView.tag == 253)
                    {
                            alertView = tempView;
                            break;
                    }
            }

            if (alertView)
            {
                    // clear tag
                    alertView.tag = 0;

                    // animate out of position
                    [UIView animateWithDuration:(animated ? 0.5 : 0.0) animations:^{
                            [alertView setFrame:CGRectMake(0, self.view.frame.size.height, alertView.frame.size.width, alertView.frame.size.height)];
                    }];      
            }
    }

    @end

4
参考までに、dismissメソッドで自分でサブビューをループする必要はありません。フレームワークは[self.viewviewWithTag:253]でそれを行います。
SteveB 2012年

この例のDaveWoodのカテゴリは、ビューをそのまま表示します。したがって、半透明の効果を得るには、xibのビューのAlpha設定の背景を1未満に設定する必要もあります。
バジルバーク2012

このカテゴリには、テーブルビューなどのスクロール可能なビューの上に表示するときに問題があります。スクロールは機能します。それは良くないね。ユーザーは、表示されたビューを画面外にスクロールできます。基になる表示ビューのコンテンツが画面に表示されます。
バジルバーク

それ以来、このカテゴリを更新しました。ここでコードを取得できます:gist.github.com/4423365。私はあなたが説明するスクロールの問題なしにテーブルビューとコレクションビューでそれを使用します。
デイブウッド

2

多くの研究の後、これは私たちの問題を解決し、私たちの目的を果たすように見えます。

識別子を使用して、送信元VCから宛先VCへのセグエを作成します。

たとえば、「goToDestinationViewController」を使用すると、作業が簡単になります。現在のビューコントローラ、つまり、透明なビューの背後にあるソースをソース、宛先を宛先として考えてみましょう。

現在、viewDidLoadのソースVCにあります:またはview

performSegueWithIdentifier("goToDestinationViewController", sender: nil)

中途半端です。次に、ストーリーボードに移動します。セグエをクリックします。これは次のようになります: セグエ

オプションを表示されているものに変更します。

今、本当の解決策が来ます。

デスティネーションビューコントローラーのviewDidLoadにこのコードを追加します。

self.modalPresentationStyle = .Custom

.................................................。 .......................それは簡単です........................。 ........................................。


1
self.modalPresentationStyle = .customSwift 3、Xcode 8で、背景が透明な実際のビューコントローラーをモーダルに表示する場合、設定は機能します。唯一の問題は、表示するビューコントローラーがタブバーコントローラーに埋め込まれている場合、タブバーが透明な前に表示されることです。背景ビュー。
mtso 2016

したがって、タブバーを使用している場合は、表示しているViewControllertabBarController.tabBar.isHiddenをに設定する必要がありtrueます。
mtso 2016

1

別の方法は、「コンテナビュー」を使用することです。アルファを1未満にして、シークを埋め込むだけです。XCode 5、ターゲットiOS7。

画像を表示できない、評判が悪い)))

iOS6から利用可能なコンテナビュー。


1

このコードは、iOS6およびiOS7のiPhoneで正常に機能します。

presentedVC.view.backgroundColor = YOUR_COLOR; // can be with 'alpha'
presentingVC.modalPresentationStyle = UIModalPresentationCurrentContext;
[presentingVC presentViewController:presentedVC animated:YES completion:NULL];

しかし、この方法に沿って、「下からスライド」のアニメーションを失います。


これはiPhoneでは機能しません。下のビューはまだ消えています。modalPresentationStyleはiPadにのみ適用されると思います。
jessepinho 2013年

必要に応じて、結果の効果の画面を送信できます。実装に問題がある可能性があります。
malex 2013年

ああ...それは、ビューコントローラがフルスクリーンである必要があることに気付いていなかったためです。(T氏のコメントを参照してください。)
jessepinho 2013年

1

iOS 7以降向けのこのエレガントでシンプルなソリューションを見つけました!

iOS 8の場合、AppleはUIModalPresentationOverCurrentContextを追加しましたが、iOS 7以前では機能しないため、私の場合は使用できませんでした。

カテゴリを作成して、次のコードを入力してください。

.hファイル

typedef void(^DismissBlock)(void);

@interface UIViewController (Ext)

- (DismissBlock)presentController:(UIViewController *)controller
              withBackgroundColor:(UIColor *)color
                         andAlpha:(CGFloat)alpha
                presentCompletion:(void(^)(void))presentCompletion;

@end

.mファイル

#import "UIViewController+Ext.h"

@implementation UIViewController (Ext)

- (DismissBlock)presentController:(UIViewController *)controller
              withBackgroundColor:(UIColor *)color
                         andAlpha:(CGFloat)alpha
                presentCompletion:(void(^)(void))presentCompletion
{
    controller.modalPresentationStyle = UIModalPresentationCustom;

    UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
    __block UIView *overlay = [[UIView alloc] initWithFrame:keyWindow.bounds];
    if (color == nil) {
        color = [UIColor blackColor];
    }
    overlay.backgroundColor = color;
    overlay.alpha = alpha;

    if (self.navigationController != nil) {
        [self.navigationController.view addSubview:overlay];
    }
    else if (self.tabBarController != nil) {
        [self.tabBarController.view addSubview:overlay];
    }
    else {
        [self.view addSubview:overlay];
    }

    self.modalPresentationStyle = UIModalPresentationCurrentContext;
    [self presentViewController:controller
                       animated:true
                     completion:presentCompletion];

    DismissBlock dismissBlock = ^(void) {
        [self dismissViewControllerAnimated:YES completion:nil];
        [UIView animateWithDuration:0.25
                         animations:^{
                             overlay.alpha = 0;
                         } completion:^(BOOL finished) {
                             [overlay removeFromSuperview];
                         }];
    };
    return dismissBlock;
}

@end

注:navigationContoller、tabBarControllerでも機能します。

使用例:

       // Please, insure that your controller has clear background
       ViewController *controller = [ViewController instance];
        __block DismissBlock dismissBlock = [self presentController:controller
                                                withBackgroundColor:[UIColor blackColor]
                                                           andAlpha:0.5
                                                  presentCompletion:nil];
        // Supposed to be your controller's closing callback
        controller.dismissed = ^(void) {
            dismissBlock();
        };

楽しめ!そして、いくつかのフィードバックを残してください。


0

これは私がこれまでに見つけた最良で最もクリーンな方法です:

@protocol EditLoginDelegate <NSObject>

- (void)dissmissEditLogin;

@end

- (IBAction)showtTransparentView:(id)sender {

    UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"foo bar"
                                                         delegate:self
                                                cancelButtonTitle:@"cancel"
                                           destructiveButtonTitle:@"destructive"
                                                otherButtonTitles:@"ok", nil];

    [actionSheet showInView:self.view];

}

- (void)willPresentActionSheet:(UIActionSheet *)actionSheet{

    UIStoryboard *loginStoryboard     = [UIStoryboard storyboardWithName:@"Login" bundle:nil];
    self.editLoginViewController      = [loginStoryboard instantiateViewControllerWithIdentifier:@"EditLoginViewController"];

    self.editLoginViewController.delegate = self;

    [self.editLoginViewController viewWillAppear:NO];
    [actionSheet addSubview:self.editLoginViewController.view];
    [self.editLoginViewController viewDidAppear:NO];
}


0

複数の方法を使用して解決しようとしましたが、それでも失敗しました。次のコードが最終的に実装されました。

Swiftによる解決:

// A.swift init method
modalPresentationStyle = .currentContext // or overCurrentContent
modalTransitionStyle = .crossDissolve // dissolve means overlay

次にBビューコントローラで:

// B.swift
let a = A()
self.present(a, animated: true, completion: nil)

ViewControllerのビューのbackgroundColorも透明にする必要があります。view.backgroundColor = UIColor.clear
マイケル・ヘンリー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.