iOS 8自定义视图控制器演示:在动画期间更改呈现的VC的大小

时间:2014-08-26 00:52:10

标签: objective-c ios8 custom-transition

我在桌面视图中使用一系列卡片编写应用程序,类似于启用Google即时贴图时iOS版Google应用程序的布局。当用户点击卡片时,应该有一个自定义过渡到新的视图控制器,这基本上是看起来更大的卡片,几乎填满了屏幕,并且它有更多细节。自定义过渡本身应该看起来像卡片向上动画并且尺寸越来越大,直到达到最终尺寸和位置,现在是持有卡片的新视图控制器。

我一直在尝试使用自定义视图控制器转换来解决这个问题。当点击卡时,我使用UIModalPresentationCustom启动自定义视图控制器转换,并设置转换委托,它本身会自定义动画师和自定义UIPresentationController。在animateTransition:中,我将新视图控制器的视图添加到容器视图中,最初将框架设置到卡片框架(所以看起来卡片是还在那里,没有变化)。然后我尝试执行一个动画,其中所呈现的视图的框架增大并改变位置,使其移动到最终位置。

以下是我的一些代码,它完成了我上面所描述的内容 - 我试图保持简短和甜蜜,但如果需要,我可以提供更多信息:

转移代表

-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {

    // NOWAnimationDelegate is my own custom protocol which defines the method for asking the presenting VC for the tapped card's frame.
    UIViewController<NOWAnimationDelegate> *fromVC = (UIViewController<NOWAnimationDelegate> *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *finalVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey];

    // Ask the presenting view controller for the frame of the tapped card - this method works.
    toView.frame = [fromVC rectForSelectedCard];

    [transitionContext.containerView addSubview:toView];

    CGRect finalRect = [transitionContext finalFrameForViewController:finalVC];

    [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
        toView.frame = finalRect;
    }completion:^(BOOL finished) {
        [transitionContext completeTransition:YES];
    }];
}

自定义UIPresentationController

-(CGSize)sizeForChildContentContainer:(id<UIContentContainer>)container withParentContainerSize:(CGSize)parentSize {
    return CGSizeMake(0.875*parentSize.width, 0.875*parentSize.height);
}

-(CGRect)frameOfPresentedViewInContainerView {
    CGRect presentedViewFrame = CGRectZero;
    CGRect containerBounds = self.containerView.bounds;

    presentedViewFrame.size = [self sizeForChildContentContainer:(UIView<UIContentContainer> *)self.presentedView withParentContainerSize:containerBounds.size];
    presentedViewFrame.origin.x = (containerBounds.size.width - presentedViewFrame.size.width)/2;
    presentedViewFrame.origin.y = (containerBounds.size.height - presentedViewFrame.size.height)/2 + 10;

    return presentedViewFrame;
}

我发现的是新动画在动画开始时自动立即设置为最终尺寸,然后动画就是动画的新视图向上。使用断点,我注意到在frameOfPresentedViewInContainerView调用期间调用了[transitionContext.containerView addSubview:toView],这可能解释了为什么会发生这种情况 - frameOfPresentedViewInContainerView返回&#34;要分配的帧矩形在动画结尾处呈现的视图&#34;根据UIPresentationController文档。

但是,我不确定如何继续,或者它是否真的有可能。我已经看到的所有自定义视图控制器转换的示例都具有所呈现的视图控制器的最终大小,在动画期间静态且不变。有没有办法在动画期间执行自定义视图控制器转换,并改变呈现视图的大小,或者我是否必须以不同的方式处理此问题?

3 个答案:

答案 0 :(得分:1)

基本上您需要做的是使用Transition Delegate中的CGAffineTransform动画化toView.transform。要做的步骤:

  1. 在制作动画之前,请设置您的toView.frame =未显示的框架
  2. 创建,比方说,CGAffineTransformMakeScale可以从隐藏框架缩放到您想要的最终呈现框架
  3. 在动画块上将toView.transform设置为您在步骤2中创建的变换

答案 1 :(得分:1)

正如Aditya所提到的,CGAffineTransform是前往这里的方式。

我现在正在使用它保持宽度:

    CGFloat targetscale=initialHeight/finalHeight;
    CGFloat targetyoffset=(finalHeight-(finalHeight*targetscale))/2;
    int targety=roundf(initialPosition-targetyoffset);

    CGAffineTransform move=CGAffineTransformMakeTranslation(0, targety);
    CGAffineTransform scale=CGAffineTransformMakeScale(1,targetscale);
    toView.transform=CGAffineTransformConcat(scale,move);

这将输入视图定位到考虑所确定的比例,然后同时执行两个变换,以便视图缩放&amp;移动到最终位置和大小。

然后你只需设置

toView.transform=CGAffineTransformIdentity;

在动画块中,它将缩放到最终位置和大小。

请注意,这仅在垂直方向上移动和缩放,但可以适应所有方向的缩放:

+(CGAffineTransform)transformView:(UIView*)view toTargetRect:(CGRect)rect{

  CGFloat targetscale=rect.size.height/view.frame.size.height;

  CGFloat targetxoffset=(view.frame.size.width-(view.frame.size.width*targetscale))/2;
  int targetx=roundf(rect.origin.x-view.frame.origin.x-targetxoffset);

  CGFloat targetyoffset=(view.frame.size.height-(view.frame.size.height*targetscale))/2;
  int targety=roundf(rect.origin.y-view.frame.origin.y-targetyoffset);

  CGAffineTransform move=CGAffineTransformMakeTranslation(targetx, targety);
  CGAffineTransform scale=CGAffineTransformMakeScale(targetscale,targetscale);

  return CGAffineTransformConcat(scale, move);

}

并且不要忘记将单元格的矩形变换为全局坐标空间,因此整个窗口的起始帧正确,而不仅仅是表格中的单元格位置。

CGRect cellRect=[_tableView rectForRowAtIndexPath:[_tableView indexPathForSelectedRow]];

cellRect=[self.tableView convertRect:cellRect toView:presenting.view];

希望这有帮助!

答案 2 :(得分:0)

Apple提供了一个wwdc示例应用程序“LookInside”,随附谈话228:“查看演示控制器内部”。它具有2个自定义演示文稿,其中一个动画显示所呈现的视图控制器的大小。查看该代码应该可以帮助您;)