2012-08-25 39 views
3

我想放在一起一个简单的容器视图控制器,这将允许我从任何方向呈现子视图控制器(从右侧像标准导航控制器,也从顶部,底部和左侧。从动画视图停止transitionFormViewControllerWillAppear

发展新世纪的iOS 5中,我使用的父/子视图控制器的关系,并使用transitionFromViewController与自定义动画块在视图中滑动。

所有消息(viewWillAppear中,等)全部通过上正确的儿童视图控制器,但问题是,例如viewWillAppear似乎从一个动画循环内调用(即当我设置动画属性 - 如子视图控制器的视图的backgroundColor或子视图框架时,它们实际上是动画的)。我不想要这种行为,因为我希望在显示视图控制器之前使用viewWillAppear方法执行初始化。我不想让这段代码变成动画。

这里是我的代码的简化版本:

@implementation ContainerViewController 
@synthesize currentViewController; 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    self.view.backgroundColor = [UIColor yellowColor]; 

    self.currentViewController = [[SimpleViewController alloc] init]; 
    [self addChildViewController:self.currentViewController]; 
    self.currentViewController.view.frame = self.view.bounds; 
    [self.view addSubview:self.currentViewController.view]; 
} 

- (void) slideViewController { 
    UIViewController* previousViewController = self.currentViewController; 

    UIViewController* viewController = [[SimpleViewController alloc] init]; 
    viewController.view.frame = CGRectOffset(self.view.bounds, self.view.bounds.size.width, 0); 
    [self addChildViewController:viewController]; 
    [previousViewController willMoveToParentViewController:nil]; 

    [self transitionFromViewController:previousViewController toViewController:viewController duration:1.0 options:UIViewAnimationOptionTransitionNone animations:^{ 
     viewController.view.frame = self.view.bounds; 
    } completion:^(BOOL finished) { 
     [previousViewController removeFromParentViewController]; 
     [viewController didMoveToParentViewController:self]; 
    }]; 

    self.currentViewController = viewController; 
} 

- (void) loop { 
    double delayInSeconds = 2.0; 
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
     [self slideViewController]; 
     [self loop]; 
    }); 
} 

- (void)viewDidAppear:(BOOL)animated { 
    [self loop]; 
} 

@end 


@implementation SimpleViewController 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    self.view.backgroundColor = [UIColor whiteColor]; 
} 

- (void)viewWillAppear:(BOOL)animated { 
    CGFloat red = (arc4random()%256)/255.0; 
    CGFloat green = (arc4random()%256)/255.0; 
    CGFloat blue = (arc4random()%256)/255.0; 
    self.view.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1]; 
} 

@end 

如果您尝试运行这段代码,你会看到从右边一个新的视图控制器幻灯片。问题是该视图控制器视图的backgroundColor从白色变为随机颜色(请参阅viewWillAppear方法SimpleViewController)。我希望该视图的backgroundColor将立即设置,而不是动画。

+0

不能在slideViewController方法中设置背景颜色,在该方法中您将SimpleViewController分配给init并设置其视图的框架? – rdelmar

+0

我教过这些,但我真的想保持能够分离代码的逻辑。在子视图控制器中,我希望在显示视图时初始化视图,而不是在容器视图控制器中进行初始化。此外,万一我会从不同的容器视图控制器类呈现相同的子视图控制器类,我不想复制初始化代码。 – quentinadam

回答

2

我发现一种解决方法,通过禁用在viewWillAppear中方法属性的动画(参见Disabling implicit animations in -[CALayer setNeedsDisplayInRect:]线程详情)

的代码可以包裹CATransaction内提交修改而不动画。

- (void)viewWillAppear:(BOOL)animated { 
    [CATransaction begin]; 
    [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; 

    CGFloat red = (arc4random()%256)/255.0; 
    CGFloat green = (arc4random()%256)/255.0; 
    CGFloat blue = (arc4random()%256)/255.0; 

    self.view.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1]; 

    [CATransaction commit]; 
} 

但是我不知道其他人已经遇到了这个问题,如果有更好的方法来解决呢?

0

再想一想,我同意你的评论,最好是把孩子控制器的所有逻辑都保存在它的类中。因此,在您的子控制器中覆盖init(或者可能是viewDidLoad会起作用),并设置您想要的任何属性 - 这应该在动画发生之前设置事件。

+0

这将工作,但我希望能够执行一些初始化代码,每次视图控制器显示。非常像标准表格视图和导航控制器:当您从表格中选择一个项目时,您会在详细视图控制器中看到详细信息。标准做法(来自Apple文档)是重用相同的详细视图控制器对象并在viewWillAppear中执行初始化代码。这里的问题是,当使用自定义视图控制器的遏制时,viewWillAppear方法是动画的,每当你开始移动子视图时,看起来很有趣。 – quentinadam