如何在Objective-C中将模态背景颜色更改为透明

9
我希望能够创建一个模态视图并给它设置透明的背景色,这样用户就可以看到它后面的视图。

1
你可以使用[UIColor clearColor]; - Raxit
你使用的是哪种模态对话框? - Eiko
在你的问题中,你提到了“我希望用户可以看到模态框后面的视图。”这是正确的吗?还是你想说其他的事情。请描述一下你想要做什么? - Raxit
@Raxit:我使用了表单表格模态,因此模态位于透明视图之间。从那个透明视图中,我们可以看到后面的视图。所以,我希望我的模态框能够像那个透明视图一样。当我使用清晰颜色时,只会显示灰色而不是模态框后面的视图。 - Rizki
显示剩余2条评论
5个回答

10

好的,presentModalViewController没有提供这种行为... 但是仍然有可能实现。我创建了一个对我有效(希望对你也有效)的类别。另外,它还可以防止与同时解除和显示模态视图相关的崩溃!

头文件:

//
//  UIViewController+overView.h
//  Created by Kevin Lohman on 5/30/12.
//

#import <UIKit/UIKit.h>

@interface UIViewController (OverView)
- (void)presentOverViewController:(UIViewController *)modalViewController animated:(BOOL)animated;
- (void)dismissOverViewControllerAnimated:(BOOL)animated;
@end

实现文件:

//
//  UIViewController+overView.m
//  Created by Kevin Lohman on 5/30/12.
//

#import "UIViewController+overView.h"

@implementation UIViewController (OverView)

#define kUIViewControllerOverViewDismissNotification @"OverViewDismissNotification"

const float kUIViewControllerOverViewAnimationDuration = 0.75;
const NSInteger kUIViewControllerOverViewTag = 8008135; // Arbitrary number, so as not to conflict
- (void)overViewDismissed
{
    [self autorelease];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:kUIViewControllerOverViewDismissNotification object:self.view];
}

- (void)presentOverViewController:(UIViewController *)modalViewController animated:(BOOL)animated
{
    UIView *toView = self.view;

    CGRect finalRect = CGRectIntersection([[UIScreen mainScreen] applicationFrame], self.view.frame); // Make sure it doesn't go under menu bar
    modalViewController.view.frame = finalRect;
    modalViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
    modalViewController.view.tag = kUIViewControllerOverViewTag+modalViewController.modalTransitionStyle; // Hiding some info here :)

    if(animated)
    {
        switch(modalViewController.modalTransitionStyle)
        {
            // Currently only cross dissolve and cover vertical supported... if you add support let me know.
            case UIModalTransitionStyleCrossDissolve:
            {
                float beforeAlpha = modalViewController.view.alpha;
                modalViewController.view.alpha = 0;
                [toView addSubview:modalViewController.view];
                [UIView animateWithDuration:kUIViewControllerOverViewAnimationDuration animations:^{
                    modalViewController.view.alpha = beforeAlpha;
                }];
                break;
            }
            case UIModalTransitionStyleCoverVertical:
            default:
            {
                modalViewController.view.frame = CGRectMake(modalViewController.view.frame.origin.x, modalViewController.view.frame.size.height, 
                                                            modalViewController.view.frame.size.width, modalViewController.view.frame.size.height);
                [toView addSubview:modalViewController.view];
                [UIView animateWithDuration:kUIViewControllerOverViewAnimationDuration animations:^{
                    modalViewController.view.frame = finalRect;
                }];
                break;
            }
        }
    }
    else {
        [toView addSubview:modalViewController.view];
    }

    [modalViewController retain]; // Keep it around until we dismiss it.
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(overViewDismissed) name:kUIViewControllerOverViewDismissNotification object:modalViewController.view]; // Release will happen when this notification is posted
}

NSInteger transitionStyleForTag(tag)
{
    if (tag >= kUIViewControllerOverViewTag && tag <= kUIViewControllerOverViewTag+UIModalTransitionStylePartialCurl)
    {
        return tag-kUIViewControllerOverViewTag;
    }
    else {
        return -1; // Not a Over View
    }
}

- (void)dismissOverViewControllerAnimated:(BOOL)animated
{
    UIView *overView = transitionStyleForTag(self.view.tag) >= 0 ? self.view : nil; // Can dismiss ourselves
    for(UIView *subview in self.view.subviews)
    {
        if(transitionStyleForTag(subview.tag) >= 0)
            overView = subview; // Keep going, lets dismiss last presented first
    }
    if(!overView) return; // None to dismiss

    if(animated)
    {
        switch(transitionStyleForTag(overView.tag))
        {
            // Currently only cross dissolve and cover vertical supported... if you add support let me know.
            case UIModalTransitionStyleCrossDissolve:
            {
                float beforeAlpha = overView.alpha;
                [UIView animateWithDuration:kUIViewControllerOverViewAnimationDuration animations:^{
                    overView.alpha = 0;
                } completion:^(BOOL finished) {
                    [overView removeFromSuperview];
                    overView.alpha = beforeAlpha;
                    [[NSNotificationCenter defaultCenter] postNotificationName:kUIViewControllerOverViewDismissNotification object:overView];
                }];
                break;
            }
            case UIModalTransitionStyleCoverVertical:
            default:
            {
                [UIView animateWithDuration:kUIViewControllerOverViewAnimationDuration animations:^{
                    overView.frame = CGRectMake(0, overView.frame.size.height, overView.frame.size.width, overView.frame.size.height);
                } completion:^(BOOL finished) {
                    [overView removeFromSuperview];
                    [[NSNotificationCenter defaultCenter] postNotificationName:kUIViewControllerOverViewDismissNotification object:overView];
                }];
                break;
            }
        }
    }
    else {
        [overView removeFromSuperview];
        [[NSNotificationCenter defaultCenter] postNotificationName:kUIViewControllerOverViewDismissNotification object:overView];
    }
}
@end

然后使用它时,只需使用presentOverViewController而不是presentModalViewController,并使用dismissOverViewController而不是dissmissModalViewController。

有几个限制:

  1. 您必须呈现到最根部的视图控制器,因此如果您想覆盖整个屏幕并且您在UINavigationController中拥有VC,则将其呈现给导航控制器。
  2. 旧版iOS(4.0左右)可能存在旋转问题(我没有看到任何问题)
  3. 目前仅处理交叉溶解和垂直覆盖动画。

好整洁的解决方案,谢谢!不过还有两点需要注意。
首先,请注意通知处理程序overViewDismissed释放了self而不是模态视图控制器,这会导致崩溃。请完全删除通知代码(addObserver/postNotification),并在present/dismiss方法之外管理模态视图控制器的内存。 其次,[[UIScreen mainScreen] applicationFrame]不总是返回正确的框架大小。我使用self.view.superview.frame代替(参见this answer)。
- Vladimir Grigorov
@VladimirGrigorov 嘿,谢谢你的提示,似乎有些逻辑错误。我不记得我把这个放在哪个代码库中了,但是请想象一下我已经在本地修复了它......如果您仍然在某个地方编译/运行已修复的版本,请根据您的发现编辑答案?我可以更改它(只需将 [self autorelease] 更改为 [self.parentViewController autorelease]?我盲目地进行更改风险很大 :) - BadPirate
我已经按照我之前的评论所述删除了通知代码,该版本已经通过测试。 - Vladimir Grigorov
还有一个库可以实现这个功能:https://github.com/martinjuhasz/MJPopupViewController - Shiki

9
对我来说,答案只需要在呈现模态视图控制器之前添加一行代码到父视图控制器中:
self.modalPresentationStyle = UIModalPresentationCurrentContext;

这将阻止父视图在模态视图添加后被移除。

6
这段代码的作用是设置当前视图控制器的导航控制器的模态展示样式为UIModalPresentationCurrentContext。 - surfrider
你在父视图控制器上设置了吗?然后你使用了 presentViewController:animated:completion: 命令吗?我必须承认,我只在iPad上尝试过这个,而不是iPhone,但我不认为会有什么区别。 - jowie
这正是我正在寻找的。谢谢!运行得非常完美。 - Justin Whitney

3

iOS不支持在模态视图中使用透明度。


1
是的,我认为目前 iOS 并不支持模态中的透明度。感谢您的回答,machunter。 :) - Rizki
好的,知道这个并没有什么帮助。 - Boris Gafurov

0

可能你想将一个UIView作为覆盖层添加到当前视图中,但是希望它全屏显示,并且具有透明或半透明的背景。请参考这个问题的第一个答案:

disable elements on UIView behind modal UIView


0
你需要像反着来一样去操作。先加载你的模态视图,然后手动添加所有元素为Subview,这样它们就不会被遮挡住了。 是的,这需要写很多代码,但是完全可行。 我曾经为播放电影时在屏幕上添加额外元素而设置小的框架大小,并将一些按钮和TextView放置在它周围作为Subview。 B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接