复制iOS邮件应用程序的撰写function的样式

我正在iOS 8上构build一个应用程序,并希望在创build新电子邮件/消息时复制iOS邮件应用程序的function。 如下所示:组合视图控制器显示在收件箱视图控制器的顶部,但组合视图控制器不占用整个屏幕。 有没有比视图控制器的帧更容易的方法来做到这一点? 谢谢!

在这里输入图像说明

这个效果可以通过UIPresentationController实现,在iOS 8中可用。苹果有一个关于这个主题的WWDC '14video,以及在这篇文章底部发现的一些有用的示例代码(我在这里发布的原始链接不再有效)。

*演示被称为“LookInside:演示控制器适应性和自定义animation对象”。 苹果的代码中存在一些对应于过时的API使用的错误,可以通过将破坏的方法名称(在多个位置)更改为以下来解决:

initWithPresentedViewController:presentingViewController:

以下是可以在iOS 8邮件应用程序上复制animation的方法。 为了达到预期的效果,下载我上面提到的项目,然后你所要做的就是改变一些东西。

首先,转到AAPLOverlayPresentationController.m,并确保已经实现了frameOfPresentedViewInContainerView方法。 我看起来像这样:

 - (CGRect)frameOfPresentedViewInContainerView { CGRect containerBounds = [[self containerView] bounds]; CGRect presentedViewFrame = CGRectZero; presentedViewFrame.size = CGSizeMake(containerBounds.size.width, containerBounds.size.height-40.0f); presentedViewFrame.origin = CGPointMake(0.0f, 40.0f); return presentedViewFrame; } 

关键是你希望presentViewController的框架从屏幕的顶部偏移,所以你可以实现一个视图控制器与另一个视图控制器的外观(没有模态完全覆盖了presentationViewController)。

接下来,在animateTransition:findanimateTransition:方法,并用下面的代码replace代码。 你可能想根据你自己的代码来调整一些东西,但总的来说,这似乎是解决scheme:

 - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext { UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIView *fromView = [fromVC view]; UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIView *toView = [toVC view]; UIView *containerView = [transitionContext containerView]; BOOL isPresentation = [self isPresentation]; if(isPresentation) { [containerView addSubview:toView]; } UIViewController *bottomVC = isPresentation? fromVC : toVC; UIView *bottomPresentingView = [bottomVC view]; UIViewController *topVC = isPresentation? toVC : fromVC; UIView *topPresentedView = [topVC view]; CGRect topPresentedFrame = [transitionContext finalFrameForViewController:topVC]; CGRect topDismissedFrame = topPresentedFrame; topDismissedFrame.origin.y += topDismissedFrame.size.height; CGRect topInitialFrame = isPresentation ? topDismissedFrame : topPresentedFrame; CGRect topFinalFrame = isPresentation ? topPresentedFrame : topDismissedFrame; [topPresentedView setFrame:topInitialFrame]; [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0 usingSpringWithDamping:300.0 initialSpringVelocity:5.0 options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState animations:^{ [topPresentedView setFrame:topFinalFrame]; CGFloat scalingFactor = [self isPresentation] ? 0.92f : 1.0f; //this is the magic right here bottomPresentingView.transform = CGAffineTransformScale(CGAffineTransformIdentity, scalingFactor, scalingFactor); } completion:^(BOOL finished){ if(![self isPresentation]) { [fromView removeFromSuperview]; } [transitionContext completeTransition:YES]; }]; } 

目前,我还没有iOS 8之前的操作系统版本的解决scheme,但如果您想出一个答案,请随时添加一个答案。 谢谢。

更新:

看起来好像上面的链接不再起作用。 同样的项目可以在这里find: https : //developer.apple.com/library/ios/samplecode/LookInside/LookInsidePresentationControllersAdaptivityandCustomAnimatorObjects.zip

对于未来的旅行者来说,Brian的post非常出色,但是UIPresentationController(这方便了这个animation)里面有相当多的关于这方面的信息,我强烈推荐你看看。 我创build了一个包含工作的Swift 1.2版本的iOS邮件应用程序的撰写animation的回购。 我还在自述文件中提供了大量的相关资源。 请在这里查看:
https://github.com/kbpontius/iOSComposeAnimation

我不能评论MariSa的答案,但我改变了他们的代码,使其实际工作(可以使用一些清理,但它对我来说)

(Swift 3)

这里是链接: http : //dativestudios.com/blog/2014/06/29/presentation-controllers/

在CustomPresentationController.swift中:

更新dimmingView(使其为黑色而不是红色,如示例中所示)

 lazy var dimmingView :UIView = { let view = UIView(frame: self.containerView!.bounds) view.backgroundColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.5) view.alpha = 0.0 return view }() 

按照MariSa的指示更新frameOfPresentedViewInContainerView:

 override var frameOfPresentedViewInContainerView : CGRect { // We don't want the presented view to fill the whole container view, so inset it's frame let frame = self.containerView!.bounds; var presentedViewFrame = CGRect.zero presentedViewFrame.size = CGSize(width: frame.size.width, height: frame.size.height - 40) presentedViewFrame.origin = CGPoint(x: 0, y: 40) return presentedViewFrame } 

在CustomPresentationAnimationController中:

更新animateTransition(开始/结束帧不同于MariSa的答案)

  func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from) let fromView = fromVC?.view let toVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) let toView = toVC?.view let containerView = transitionContext.containerView if isPresenting { containerView.addSubview(toView!) } let bottomVC = isPresenting ? fromVC : toVC let bottomPresentingView = bottomVC?.view let topVC = isPresenting ? toVC : fromVC let topPresentedView = topVC?.view var topPresentedFrame = transitionContext.finalFrame(for: topVC!) let topDismissedFrame = topPresentedFrame topPresentedFrame.origin.y -= topDismissedFrame.size.height let topInitialFrame = topDismissedFrame let topFinalFrame = isPresenting ? topPresentedFrame : topDismissedFrame topPresentedView?.frame = topInitialFrame UIView.animate(withDuration: self.transitionDuration(using: transitionContext), delay: 0, usingSpringWithDamping: 300.0, initialSpringVelocity: 5.0, options: [.allowUserInteraction, .beginFromCurrentState], //[.Alert, .Badge] animations: { topPresentedView?.frame = topFinalFrame let scalingFactor : CGFloat = self.isPresenting ? 0.92 : 1.0 bottomPresentingView?.transform = CGAffineTransform.identity.scaledBy(x: scalingFactor, y: scalingFactor) }, completion: { (value: Bool) in if !self.isPresenting { fromView?.removeFromSuperview() } }) if isPresenting { animatePresentationWithTransitionContext(transitionContext) } else { animateDismissalWithTransitionContext(transitionContext) } } 

更新animatePresentationWithTransitionContext(不同的框架位置再次):

 func animatePresentationWithTransitionContext(_ transitionContext: UIViewControllerContextTransitioning) { let containerView = transitionContext.containerView guard let presentedController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to), let presentedControllerView = transitionContext.view(forKey: UITransitionContextViewKey.to) else { return } // Position the presented view off the top of the container view presentedControllerView.frame = transitionContext.finalFrame(for: presentedController) presentedControllerView.center.y += containerView.bounds.size.height containerView.addSubview(presentedControllerView) // Animate the presented view to it's final position UIView.animate(withDuration: self.duration, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0.0, options: .allowUserInteraction, animations: { presentedControllerView.center.y -= containerView.bounds.size.height }, completion: {(completed: Bool) -> Void in transitionContext.completeTransition(completed) }) } 

对于Swift 2,你可以按照这个教程: http : //dativestudios.com/blog/2014/06/29/presentation-controllers/并replace:

 override func frameOfPresentedViewInContainerView() -> CGRect { // We don't want the presented view to fill the whole container view, so inset it's frame let frame = self.containerView!.bounds; var presentedViewFrame = CGRectZero presentedViewFrame.size = CGSizeMake(frame.size.width, frame.size.height - 40) presentedViewFrame.origin = CGPointMake(0, 40) return presentedViewFrame } 

和:

 func animateTransition(transitionContext: UIViewControllerContextTransitioning) { let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) let fromView = fromVC?.view let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) let toView = toVC?.view let containerView = transitionContext.containerView() if isPresenting { containerView?.addSubview(toView!) } let bottomVC = isPresenting ? fromVC : toVC let bottomPresentingView = bottomVC?.view let topVC = isPresenting ? toVC : fromVC let topPresentedView = topVC?.view var topPresentedFrame = transitionContext.finalFrameForViewController(topVC!) let topDismissedFrame = topPresentedFrame topPresentedFrame.origin.y += topDismissedFrame.size.height let topInitialFrame = isPresenting ? topDismissedFrame : topPresentedFrame let topFinalFrame = isPresenting ? topPresentedFrame : topDismissedFrame topPresentedView?.frame = topInitialFrame UIView.animateWithDuration(self.transitionDuration(transitionContext), delay: 0, usingSpringWithDamping: 300.0, initialSpringVelocity: 5.0, options: [.AllowUserInteraction, .BeginFromCurrentState], //[.Alert, .Badge] animations: { topPresentedView?.frame = topFinalFrame let scalingFactor : CGFloat = self.isPresenting ? 0.92 : 1.0 bottomPresentingView?.transform = CGAffineTransformScale(CGAffineTransformIdentity, scalingFactor, scalingFactor) }, completion: { (value: Bool) in if !self.isPresenting { fromView?.removeFromSuperview() } }) if isPresenting { animatePresentationWithTransitionContext(transitionContext) } else { animateDismissalWithTransitionContext(transitionContext) } }