9

我使用下面的代码来展示一个视图控制器。我的问题是:动画完成后,透明的主背景变成不透明的黑色。

我该如何解决这个问题并让它保持清晰的颜色?

UIViewController *menuViewController=[[UIViewController alloc]init];
   menuViewController.view.backgroundColor=[UIColor clearColor];
   menuViewController.view.tintColor=[UIColor clearColor];
   menuViewController.view.opaque=NO;

UIView *menuView=[[UIView alloc]initWithFrame:CGRectMake(0,[UIScreen mainScreen].bounds.size.height-200,320,200)];
   menuView.backgroundColor=[UIColor redColor];

[menuViewController.view addSubview:menuView];

[self presentViewController:menuViewController animated:YES completion:nil];

更新:我正在尝试查看“自我”的内容(演示者视图控制器的视图)。

4

6 回答 6

26

iOS 15 更新

Apple 引入了一个新的 API,即 UISheetPresentationController,这使得实现半尺寸 ( .medium()) 的工作表呈现变得相当简单。如果您追求更自定义的东西,那么原始答案就是您所需要的。

let vc = UIViewController()
if let sheet = vc.presentationController as? UISheetPresentationController {
    sheet.detents = [.medium()]
}
self.present(vc, animated: true, completion: nil)

原始答案

在 iOS 7 中,您可以呈现一个视图控制器,并且在下面仍然可以看到原始视图控制器,就像一个表单一样。为此,您需要做两件事:

  1. 将模态演示样式设置为自定义:

    viewControllerToPresent.modalPresentationStyle = UIModalPresentationCustom;
    
  2. 设置过渡委托:

    viewControllerToPresent.transitioningDelegate = self;
    

在这种情况下,我们将委托设置为 self,但它可以是另一个对象。委托需要实现协议的两个必需方法,可能像这样:

- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
    SemiModalAnimatedTransition *semiModalAnimatedTransition = [[SemiModalAnimatedTransition alloc] init];
    semiModalAnimatedTransition.presenting = YES;
    return semiModalAnimatedTransition;
}

- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
    SemiModalAnimatedTransition *semiModalAnimatedTransition = [[SemiModalAnimatedTransition alloc] init];
    return semiModalAnimatedTransition;
}

此时你可能会想,这个SemiModalAnimatedTransition类是从哪里来的。嗯,这是从teehan+lax的博客中采用的自定义实现。

这是类的标题:

@interface SemiModalAnimatedTransition : NSObject <UIViewControllerAnimatedTransitioning>
@property (nonatomic, assign) BOOL presenting;
@end

和实施:

#import "SemiModalAnimatedTransition.h"

@implementation SemiModalAnimatedTransition

- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
{
    return self.presenting ? 0.6 : 0.3;
}

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
{
    UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    
    CGRect endFrame = fromViewController.view.bounds;
    
    if (self.presenting) {
        fromViewController.view.userInteractionEnabled = NO;
        
        [transitionContext.containerView addSubview:fromViewController.view];
        [transitionContext.containerView addSubview:toViewController.view];
        
        CGRect startFrame = endFrame;
        startFrame.origin.y = endFrame.size.height;
        
        toViewController.view.frame = startFrame;
        
        [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
            fromViewController.view.tintAdjustmentMode = UIViewTintAdjustmentModeDimmed;
            toViewController.view.frame = endFrame;
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:YES];
        }];
    }
    else {
        toViewController.view.userInteractionEnabled = YES;
        
        [transitionContext.containerView addSubview:toViewController.view];
        [transitionContext.containerView addSubview:fromViewController.view];
        
        endFrame.origin.y = endFrame.size.height;
        
        [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
            toViewController.view.tintAdjustmentMode = UIViewTintAdjustmentModeAutomatic;
            fromViewController.view.frame = endFrame;
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:YES];
        }];
    }
}

@end

不是最直接的解决方案,但可以避免黑客攻击并且效果很好。自定义转换是必需的,因为默认情况下 iOS 将在转换结束时删除第一个视图控制器。

iOS 8 更新

对于 iOS 8,情况再次发生了变化。您需要做的就是使用新的演示风格.OverCurrentContext,即:

viewControllerToPresent.modalPresentationStyle = UIModalPresentationOverCurrentContext;
于 2014-05-13T06:23:05.317 回答
8

更新

在大多数情况下,您需要遵循Ric 回答中的指南,如下所示。正如他所提到的,menuViewController.modalPresentationStyle = .overCurrentContext这是保持呈现视图控制器可见的最简单的现代方法。

我保留这个答案是因为它为 OPs 问题提供了最直接的解决方案,他们已经有一个由当前视图控制器管理的视图,并且只是在寻找一种呈现它的方法,并且因为它解释了实际的原因问题。


如评论中所述,这不是透明度问题(否则您会期望背景变为白色)。当presentViewController:animated:completion:动画完成时,呈现的视图控制器实际上从视觉堆栈中移除。您看到的黑色是窗口的背景颜色。

由于您似乎只是menuViewController用作menuView简化动画的宿主,因此您可以考虑跳过menuViewController,添加menuView到现有的视图控制器视图层次结构中,然后自己制作动画。

于 2013-10-01T22:36:36.313 回答
4

这是一个相当简单的问题。无需创建自定义视图转换,您只需为正在呈现的视图控制器设置 modalPresentationStyle。此外,您应该在情节提要/通过代码中设置正在呈现的视图控制器的背景颜色(和 alpha 值)。

CustomViewController: UIViewController {
    override func viewDidLoad() {
      super.viewDidLoad()
      view.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.6)
    }
}

在呈现视图控制器的 IBAction 组件中 -

let vc = storyboard?.instantiateViewControllerWithIdentifier("customViewController") as! CustomViewController
vc.modalPresentationStyle = UIModalPresentationStyle.Custom
presentViewController(vc, animated: true, completion: nil)
于 2015-05-20T18:43:24.397 回答
1

您应该使用自 iOS 3.2起可用的属性modalPresentationStyle 。

例如:

presenterViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
[presenterViewController presentViewController:loginViewController animated:YES completion:NULL];
于 2013-10-07T10:04:35.827 回答
0

尝试使顶视图透明并在所需视图下方添加另一个视图并将该视图的背景颜色设置为黑色并设置 alpha 0.5 或您喜欢的任何不透明度级别。

于 2013-10-01T20:56:37.583 回答
0

这是一篇相当古老的帖子,多亏了 Ric 的回答,它仍然运行良好,但在 iOS 14 上运行它需要很少的修复。我想它在较低版本的 iOS 上运行良好,但我没有机会测试它,因为我的部署目标是 iOS 14。

好的,这是 Swift 中的更新解决方案:

final class SemiTransparentPopupAnimator: NSObject, UIViewControllerAnimatedTransitioning {
var presenting = false

func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
    return presenting ? 0.4 : 0.2
}

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    guard
        let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from),
        let toVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
        else {
            return
    }
    
    var endFrame = fromVC.view.bounds
    
    if presenting {
        fromVC.view.isUserInteractionEnabled = false
        
        transitionContext.containerView.addSubview(toVC.view)
        
        var startFrame = endFrame
        startFrame.origin.y = endFrame.size.height
        toVC.view.frame = startFrame
        
        UIView.animate(withDuration: transitionDuration(using: transitionContext)) {
            fromVC.view.tintAdjustmentMode = .dimmed
            toVC.view.frame = endFrame
        } completion: { _ in
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        }
    } else {
        toVC.view.isUserInteractionEnabled = true
        
        endFrame.origin.y = endFrame.size.height
        
        UIView.animate(withDuration: transitionDuration(using: transitionContext)) {
            toVC.view.tintAdjustmentMode = .automatic
            fromVC.view.frame = endFrame
        } completion: { _ in
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        }
    }
}
}
于 2021-09-16T16:10:18.303 回答