![](/img/trans.png)
[英]iOS Modal ViewController with Transparent BG and Opaque Foreground
[英]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
}
}
創建一個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,則可以按照以下步驟操作:
- 添加視圖控制器(V2),按照您希望的方式設置UI
禮物V2模態
單擊segue。 在“屬性”檢查器中,將“演示文稿”設置為“全屏幕” 。 如果你願意,刪除動畫
- 選擇V2。 在“屬性”檢查器中,將“演示文稿”設置為“全屏幕” 。 檢查定義上下文並提供上下文
- 選擇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)
我創建了一個對象來處理我稱之為“疊加模態”的表示,這意味着它保留了背景的視圖,並允許您擁有一個透明背景的模態。
它有一個簡單的方法可以做到這一點:
- (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
您希望此對象符合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
}];
這將以模態方式在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];
}
將導航的modalPresentationStyle
設置為UIModalPresentationCustom
並將您呈現的視圖控制器的背景顏色設置為清晰的顏色。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.