如何在 iOS 中呈现一个半透明(半切)的视图控制器?

     2023-03-13     263

关键词:

【中文标题】如何在 iOS 中呈现一个半透明(半切)的视图控制器?【英文标题】:How to present a semi-transparent (half-cut) viewcontroller in iOS? 【发布时间】:2013-10-01 20:50:17 【问题描述】:

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

如何解决此问题并使其保持为 clearColor?

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

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

【问题讨论】:

这不是透明度问题。动画完成后,iOS 会从屏幕上移除隐藏的视图控制器。您看到的黑色是窗口的背景颜色。我相信 iOS7 对此有一些选择。 @BrianNickel 所以你的意思是演示者视图控制器是隐藏的,直到呈现的一个被解雇?在这种情况下,我是否应该手动添加视图并使用动画将其从屏幕底部拉出来? 没错。您可以跳过menuViewController,而只是将menuView 动画到屏幕上。 您能否发布一个答案,其中提到您刚刚给出的主要解释? (无法通过呈现的视图控制器看到演示者视图控制器)。所以我将其标记为答案,其他用户可以轻松找到原因。谢谢! 不,添加的视图上的任何“交互”都由其原始视图控制器处理。但是由于它的父视图在添加到另一个视图后发生了变化,因此链接链被破坏了。为了正确传播方法调用(例如 viewDidAppear),将子控制器也添加为子控制器也很重要。 【参考方案1】:

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

    将模态展示样式设置为自定义:

    viewControllerToPresent.modalPresentationStyle = UIModalPresentationCustom;
    

    设置过渡委托:

    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;

【讨论】:

modalPresentationStyletransitionDelegate可以在parepareForSegue中设置 这应该被标记为最佳答案 这会在 iOS 8 中中断。关闭屏幕时会留下白色 删除以下行修复了问题[transitionContext.containerView addSubview:toViewController.view]; [transitionContext.containerView addSubview:fromViewController.view]; 看起来在 iOS8+ 中自定义转换在关闭时失败,因为它不希望 presentingViewController 的视图在任何时候移动到 transitionContext.containerView。当该视图被删除时,演示者会随之而来。删除这些行修复了 8+ 的解决方案(并且可能仍然适用于 7)。【参考方案2】:

更新

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

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


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

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

【讨论】:

【参考方案3】:

这是一个相当容易解决的问题。无需创建自定义视图转换,您只需为正在呈现的视图控制器设置 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)

【讨论】:

@RicSantos 谢谢!是的,这仅在 iOS 8+ 上进行了测试。【参考方案4】:

您应该使用属性 modalPresentationStyle available 从 iOS 3.2 开始。

例如:

presenterViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
[presenterViewController presentViewController:loginViewController animated:YES completion:NULL];

【讨论】:

这并不能解决问题。 PresenterViewController 仍然从屏幕上移除。 从子 VC 或其他模态展示时也有一些怪癖。 Ку.【参考方案5】:

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

【讨论】:

【参考方案6】:

这是一篇相当老的帖子,感谢 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)
        
    


【讨论】:

在 iOS 9 中呈现透明模式视图

】在iOS9中呈现透明模式视图【英文标题】:presenttransparentmodalviewiniOS9【发布时间】:2016-02-0811:14:32【问题描述】:有很多答案,但对于iOS9尤其是9.2,似乎没有一个可以正常/完美地工作。请有人帮忙。这是一个简单的场景:1)Stor... 查看详情

如何在子视图正常时获得半透明视图

】如何在子视图正常时获得半透明视图【英文标题】:Howtogetsemi-transparentviewwhilechildviewsarenormal【发布时间】:2012-02-2202:45:26【问题描述】:我有一个UIViewController派生类,我想做的是有一个不透明的子视图,而它的父视图(主UIVi... 查看详情

推送视图控制器中的半透明导航栏覆盖?

...ntroller?【发布时间】:2017-04-0113:25:54【问题描述】:我有一个内容模糊的半透明导航栏。我想推送一个带有另一个半透明导航栏但没有要模糊的内容的新视图控制器(还),所以我做了一个简单的navigationController?.pushViewController(v... 查看详情

如何使导航栏在特定视图上半透明?

】如何使导航栏在特定视图上半透明?【英文标题】:HowtomakeNavigationBartranslucentonspecificview?【发布时间】:2015-08-0420:01:14【问题描述】:我有一个包含三个视图的向下钻取层次结构,它们都嵌入在导航控制器中。我希望最后一个... 查看详情

iOS 7 半透明模态视图控制器

】iOS7半透明模态视图控制器【英文标题】:iOS7TranslucentModalViewController【发布时间】:2013-10-1105:21:23【问题描述】:iOS7上的AppStore应用使用磨砂玻璃效果,可以看到后面的景色。这是使用iOS7内置的API还是自定义代码。我希望它会... 查看详情

呈现全屏时的透明视图控制器背景

】呈现全屏时的透明视图控制器背景【英文标题】:TransparentViewControllerBackgroundWhenPresentedFullScreen【发布时间】:2017-03-1205:15:20【问题描述】:我在另一个(A)上展示了一个视图控制器(B),我希望B的背景是透明的,这样A在背景中仍... 查看详情

添加半透明视图最简单的方法(代码片段)

...的视图?解决方案:绕了很多弯路原来可以使用模态弹出一个视图控制器在iOS8之后只需要设置一个最新的属性 SecondViewController*vc=[[SecondViewControlleralloc]init];vc.modalPresentationStyle=UIModalPresentationOverCur 查看详情

轻松实现部分背景半透明的呈现效果

实现一个简单的呈现/解散动画效果,当呈现时,呈现的主要内容和背景要明显区分,背景呈现一个半透明遮罩效果,透过背景可以看到下层ViewController的内容:呈现控制器(PresentingViewController)呈现控制器即要弹出另外一个控制... 查看详情

如何在 iOS 邮件应用程序中制作一个像新邮件页面一样呈现新视图的 segue?

】如何在iOS邮件应用程序中制作一个像新邮件页面一样呈现新视图的segue?【英文标题】:HowcanmakeaseguethatpresentsthenewviewlikenewmailpageiniOSmailapp?【发布时间】:2015-02-1905:03:09【问题描述】:我制作了第一个视图,用户可以按下按钮... 查看详情

iOS Autolayout - 在半透明导航栏下方正确定位视图

...】:2013-06-2223:15:16【问题描述】:在我的故事板中,我有一个UIImageView,我想将其放置在半透明导航栏下方的固定距离处。我将视图控制器的模拟顶栏设置为半透明栏,我现在的约束是“顶部空间到Supervie 查看详情

如何创建半透明模式 UIViewController?

】如何创建半透明模式UIViewController?【英文标题】:HowcanIcreateatranslucentmodalUIViewController?【发布时间】:2009-09-3016:37:18【问题描述】:我想创建一个可重用的UIViewController子类,它可以显示为模式视图控制器,而不是任何其他视... 查看详情

如何在 iOS 6 中使用 UIPopoverBackgroundView 呈现透明弹出框

】如何在iOS6中使用UIPopoverBackgroundView呈现透明弹出框【英文标题】:HowtouseUIPopoverBackgroundViewtopresentatransparentpopoveriniOS6【发布时间】:2013-03-3009:48:07【问题描述】:我在iOS6中使用UIPopoverController来呈现UITableViewController。我正在尝... 查看详情

如何让 ScrollView 半透明并使其背后的内容具有交互性?

】如何让ScrollView半透明并使其背后的内容具有交互性?【英文标题】:HowtomakeScrollViewtranslucentandcontentbehinditinteractive?【发布时间】:2018-02-1018:45:15【问题描述】:我有一个视图控制器,其中包含一个带有一个按钮的地图视图(... 查看详情

如何呈现具有透明背景的模态视图控制器

】如何呈现具有透明背景的模态视图控制器【英文标题】:Howtopresentmodalviewcontrollerwithtransparentbackground【发布时间】:2015-04-0710:13:41【问题描述】:我使用swift以及如何呈现模态视图控制器,但他的背景是透明的。其他视图控制... 查看详情

如何在另一个图像之上获取半透明图像以在 android 中保存文本(提供屏幕截图)

】如何在另一个图像之上获取半透明图像以在android中保存文本(提供屏幕截图)【英文标题】:Howtogetasemitransparentimageontopofanotherimagetoholdtextinandroid(screenshotprovided)【发布时间】:2013-10-3117:35:44【问题描述】:我有一个使用图像... 查看详情

从 iOS 中呈现的视图控制器推送视图

...【发布时间】:2016-01-0412:39:28【问题描述】:简而言之:如何从PresentedViewControllerPushViewController?简介:我有MainViewController,其中我有一个单击按钮时的按钮,我正在呈现一个名为LoginViewController的视图。在此 查看详情

使用导航呈现自定义大小的视图控制器

】使用导航呈现自定义大小的视图控制器【英文标题】:Presentingaviewcontrollerofcustomsizewithnavigation【发布时间】:2013-04-0404:39:33【问题描述】:我想展示一个自定义大小的视图控制器,比如(500,500)。我尝试使用下面的代码来做到这... 查看详情

在 iOS7 中半透明的 UIToolbar 上挖一个洞

】在iOS7中半透明的UIToolbar上挖一个洞【英文标题】:CutaholeattranslusentUIToolbariniOS7【发布时间】:2014-09-0812:27:20【问题描述】:我需要实现带有圆孔的模糊视图,这将在iOS7+中工作我尝试使用本机UIToolbar,但在iOS7中出现一些奇怪... 查看详情