自定义容器和自定义转换
Posted
技术标签:
【中文标题】自定义容器和自定义转换【英文标题】:Custom Containers and Custom Transitions 【发布时间】:2013-11-16 21:13:25 【问题描述】:自定义转场很容易与标准容器配合使用,同时呈现模态视图控制器。但是在完全自定义的容器中使用自定义转换呢?
我想将UIViewControllerContextTransitioning
协议与我的自定义容器一起使用,并利用过渡和交互式过渡。
在UIViewControllerContextTransitioning
头文件的注释中我读到:
// The UIViewControllerContextTransitioning protocol can be adopted by custom
// container controllers. It is purposely general to cover more complex
// transitions than the system currently supports.
但我不明白如何创建上下文过渡并启动所有自定义过渡过程。
【问题讨论】:
您是否尝试在自定义容器类的推送视图控制器方法中同时调用 presentViewController:animated:completion: 和 addChildViewController:?除了 presentViewController 之外,我找不到任何会导致调用转换委托的方法。 那么您认为仅presentViewController 就可以解决问题吗?我认为这个功能与模态视图控制器相关......但可能你是对的。 如果您有时间尝试一下,请告诉它是否有效,我最近太忙了,无法尝试。 我会在接下来的几天里确定...请看一下这个问题并最终用您的评论填写答案,以便我接受它:) 非常抱歉,伙计 :( 我尝试了所有我能想到的方法,但没有用。最后,我查看了那个头文件,我读到“现在……”部分,然后我放弃了。但是感谢您提出的好问题,我在尝试找到解决方案时学到了很多东西。 【参考方案1】:这很有可能!
看看这个SO Answer。
您只需创建一个符合 UIViewControllerContextTransitioning 协议的 viewController 并使用 ViewController Containment API(addChildViewController:、willMoveToParentViewController: 等)。
当您想启动自定义过渡时,只需调用您的 transitionController 上的 [animateTransition] 方法。从那时起,它与 Apple 提供的 API 相同。
使您的自定义容器适合 Transitioning API。
实际上,ios7 中引入的所有新协议(UIViewControllerContextTransitioning 等)并不是真正需要实现您自己的完全自定义的 containerViewController。它只是提供了一个整洁的类关系和方法池。但是您可以自己编写所有内容,而无需使用任何私有 API。 ViewController Containment(在 iOS5 中引入)是您完成这项工作所需要的。
我刚刚尝试过,它甚至可以使用交互式过渡。
如果您需要一些示例代码,请告诉我,我会提供一些:)
编辑
顺便说一句,这就是 iOS 版 Facebook 和 Instagram 创建导航概念的方式。您可以在这些应用程序中滚开 NavigationBar,当“推送”新的 ViewController 时,NavigationBar 似乎在推送期间已被重置。
具有讽刺意味的是,一个月前我在 *** 上问了完全相同的问题:D
My Question
我才意识到我自己回答了:)
祝你有美好的一天!
【讨论】:
我接受了你的回答!这是正确的:) 谢谢!有一些代码示例会很棒。目前,按照您的建议,我能够在两个控制器之间执行动画,但在animateTransition
我必须手动添加每个子视图......这是正确的方法吗?使用带有标准模态控制器的自定义转换,“to-view”会自动添加到上下文视图中......所以我想知道我的代码是否正确。
我很高兴能帮助你:) 当你实现你自己的容器时,你还负责确保 childViewControllers 的视图被正确地添加和删除。通常,一次只有 1 个 childController 的视图可见,但这不是必须的。因此,当您当前添加和删除每个 childViewController 的视图时,您的代码可能是正确的;) 系统转换(如 NavigationController、Modal 等)在使用自定义转换时为您处理“fromVC”的删除。我会尽快为您整理一些示例代码:)
谢谢卡布斯!真的很难找到关于这个主题的好例子(我的意思是自定义容器 + 自定义转换:))。
@Cabus 我只想跳进去说我也很想看看这个例子!
好吧,我终于有时间为你建立一个例子。它有据可查,所以我想它会自我解释 :) 见github.com/ImJCabus/iOS7-Custom-ContainerViewController【参考方案2】:
事实上,它是这么说的,但你是不完整的:
UIViewControllerContextTransitioning 协议可以通过 自定义容器控制器。特意笼统地涵盖 比系统当前支持的更复杂的转换。为了 现在,导航推送/弹出和 UIViewController 存在/关闭 可以自定义转换。
这意味着您可以通过调用presentViewController:animated:completion:
方法来触发您的VC 的transitioningDelegate
,或者您可以在您的UINavigationControllerDelegate
类中实现navigationController:animationControllerForOperation:fromViewController:toViewController:
并返回一个符合UIViewControllerAnimatedTransitioning
协议的对象。
综上所述,提供自定义转场的方式只有两种。在我们添加子视图以创建自定义容器视图控制器时,两者都需要呈现/推送 VC。
未来,Apple 可能会按照他们在头文件中声明的第一行所说的去做,但现在你想做的似乎是不可能的。
【讨论】:
我很高兴地说你错了 :) 检查 Cabus 答案。 我想给应得的人+50,但我不能,当我想开始赏金时,它只允许我给+100。有什么帮助吗? 我真的不知道最大限制是100还是更多...我也可以开始超过100分的赏金。【参考方案3】:来自docsUIViewControllerContextTransitioning
不要在你自己的课程中采用这个协议,你也不应该 直接创建采用该协议的对象。
【讨论】:
【参考方案4】:请看MPFoldTransition,它对我有用。
您也可以使用以下类别,您可以使用它创建自己的过渡。
#import <UIKit/UIKit.h>
@interface UIView (Animation)
- (void) moveTo:(CGPoint)destination duration:(float)secs option:(UIViewAnimationOptions)option;
- (void) downUnder:(float)secs option:(UIViewAnimationOptions)option;
- (void) addSubviewWithZoomInAnimation:(UIView*)view duration:(float)secs option:(UIViewAnimationOptions)option;
- (void) removeWithZoomOutAnimation:(float)secs option:(UIViewAnimationOptions)option;
- (void) addSubviewWithFadeAnimation:(UIView*)view duration:(float)secs option:(UIViewAnimationOptions)option;
- (void) removeWithSinkAnimation:(int)steps;
- (void) removeWithSinkAnimationRotateTimer:(NSTimer*) timer;
@end
实施:
#import "UIView+Animation.h"
@implementation UIView (Animation)
- (void) moveTo:(CGPoint)destination duration:(float)secs option:(UIViewAnimationOptions)option
[UIView animateWithDuration:secs delay:0.0 options:option
animations:^
self.frame = CGRectMake(destination.x,destination.y, self.frame.size.width, self.frame.size.height);
completion:nil];
- (void) downUnder:(float)secs option:(UIViewAnimationOptions)option
[UIView animateWithDuration:secs delay:0.0 options:option
animations:^
self.transform = CGAffineTransformRotate(self.transform, M_PI);
self.alpha = self.alpha - 0.5;
completion:nil];
- (void) addSubviewWithZoomInAnimation:(UIView*)view duration:(float)secs option:(UIViewAnimationOptions)option
// first reduce the view to 1/100th of its original dimension
CGAffineTransform trans = CGAffineTransformScale(view.transform, 0.01, 0.01);
view.transform = trans; // do it instantly, no animation
[self addSubview:view];
// now return the view to normal dimension, animating this tranformation
[UIView animateWithDuration:secs delay:0.0 options:option
animations:^
view.transform = CGAffineTransformScale(view.transform, 100.0, 100.0);
completion:nil];
- (void) removeWithZoomOutAnimation:(float)secs option:(UIViewAnimationOptions)option
[UIView animateWithDuration:secs delay:0.0 options:option
animations:^
self.transform = CGAffineTransformScale(self.transform, 0.1, 0.1);
completion:^(BOOL finished)
[self removeFromSuperview];
];
// add with a fade-in effect
- (void) addSubviewWithFadeAnimation:(UIView*)view duration:(float)secs option:(UIViewAnimationOptions)option
view.alpha = 0.0; // make the view transparent
[self addSubview:view]; // add it
[UIView animateWithDuration:secs delay:0.0 options:option
animations:^view.alpha = 1.0;
completion:nil]; // animate the return to visible
// remove self making it "drain" from the sink!
- (void) removeWithSinkAnimation:(int)steps
//NSTimer *timer;
if (steps > 0 && steps < 100) // just to avoid too much steps
self.tag = steps;
else
self.tag = 50;
[NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(removeWithSinkAnimationRotateTimer:) userInfo:nil repeats:YES];
- (void) removeWithSinkAnimationRotateTimer:(NSTimer*) timer
CGAffineTransform trans = CGAffineTransformRotate(CGAffineTransformScale(self.transform, 0.9, 0.9),0.314);
self.transform = trans;
self.alpha = self.alpha * 0.98;
self.tag = self.tag - 1;
if (self.tag <= 0)
[timer invalidate];
[self removeFromSuperview];
@end
希望它能解决您的问题。享受。:)
【讨论】:
你没有理解我的问题。我的问题是“如何将 CUSTOM CONTAINER 与 CUSTOM TRANSITIONS 一起使用”。以上是关于自定义容器和自定义转换的主要内容,如果未能解决你的问题,请参考以下文章
具有自定义事件和自定义变量的 Universal Analytics 代码