自定义容器和自定义转换

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 一起使用”。

以上是关于自定义容器和自定义转换的主要内容,如果未能解决你的问题,请参考以下文章

用于组合容器和自定义逻辑的 C++ 技术/库?

具有自定义事件和自定义变量的 Universal Analytics 代码

让断点与 jest、Visual Studio 代码和自定义 typescript 转换器一起工作

Django中的日期处理注意事项和自定义时间格式转换

map的默认排序和自定义排序

Docker 提供的几种原生网络和自定义网络(11)