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

Objective c iOS 8自定义视图控制器演示:在动画期间更改演示VC的大小,objective-c,ios8,custom-transition,Objective C,Ios8,Custom Transition,我正在编写一个应用程序,在表视图中有一系列卡片,类似于启用GoogleNow卡片时Google iOS应用程序的布局。当用户点击一张卡时,应该有一个自定义的转换到一个新的视图控制器,基本上这张卡看起来更大,几乎填满了屏幕,并且它有更多的细节。自定义转换本身应该看起来像是将卡设置为向上动画并不断增大大小,直到它达到其最终大小和位置,即现在持有卡的新视图控制器 我一直在尝试使用自定义视图控制器转换来实现这一点。当点击卡时,我用UIModalPresentationCustom启动一个自定义视图控制器

我正在编写一个应用程序,在表视图中有一系列卡片,类似于启用GoogleNow卡片时Google iOS应用程序的布局。当用户点击一张卡时,应该有一个自定义的转换到一个新的视图控制器,基本上这张卡看起来更大,几乎填满了屏幕,并且它有更多的细节。自定义转换本身应该看起来像是将卡设置为向上动画并不断增大大小,直到它达到其最终大小和位置,即现在持有卡的新视图控制器

我一直在尝试使用自定义视图控制器转换来实现这一点。当点击卡时,我用
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];
    }];
}
-(void)animateTransfion:(id)transitionContext{
//NOWAnimationDelegate是我自己的自定义协议,它定义了请求呈现VC获取点击卡帧的方法。
UIViewController*fromVC=(UIViewController*)[transitionContext ViewControllerWorky:UITransitionContextFromViewControllerKey];
UIViewController*finalVC=[transitionContext ViewControllerWorky:UITransitionContextToViewControllerKey];
UIView*toView=[transitionContext viewForKey:UITransitionContextToViewKey];
//向演示视图控制器询问抽头卡的框架-此方法有效。
toView.frame=[fromVC rectForSelectedCard];
[transitionContext.containerView添加子视图:toView];
CGRect finalRect=[transitionContext finalFrameForViewController:finalVC];
[UIView animateWithDuration:[self-transitionDuration:transitionContext]动画:^{
toView.frame=finalRect;
}完成:^(布尔完成){
[transitionContext completeTransition:是];
}];
}
自定义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;
}
-(CGSize)大小ArchildContentContainer:(id)容器withParentContainerSize:(CGSize)parentSize{
返回CGSizeMake(0.875*parentSize.width,0.875*parentSize.height);
}
-(CGRect)PresentedViewContainerView框架{
CGRect presentedViewFrame=CGRectZero;
CGRect containerBounds=self.containerView.bounds;
presentedViewFrame.size=[self SizeForArchildContentContainer:(UIView*)self.presentedView with ParentContainerSize:containerBounds.size];
presentedViewFrame.origin.x=(containerBounds.size.width-presentedViewFrame.size.width)/2;
presentedViewFrame.origin.y=(containerBounds.size.height-presentedViewFrame.size.height)/2+10;
返回presentedViewFrame;
}
我发现,在动画开始时,新视图会自动设置为其最终大小,然后动画就是向上动画的新视图。使用断点,我注意到在调用
[transitionContext.containerView addSubview:toView]
期间调用了
FrameOfPresentedViewWinContainerView
,这可能解释了为什么会发生这种情况-
FrameOfPresentedViewWinContainerView
返回根据UIPresentationController文档,“要指定给动画末尾显示的视图的帧矩形”


但是,我不确定如何继续,或者是否真的有可能。我所看到的所有自定义视图控制器转换的示例都具有呈现的视图控制器的最终大小静态且在动画期间不变。是否有任何方法可以在呈现的vie大小发生变化的情况下执行自定义视图控制器转换w在动画中,还是我必须以不同的方式处理此问题?

基本上,您需要做的是在过渡代理中使用toView.transform设置动画。要执行的步骤:

  • 在设置动画之前,请设置您的toView.frame=未显示时的帧
  • 创建CGAffineTransformMakeScale,从隐藏帧缩放到所需的最终显示帧
  • 在动画块上,将设置为View.transform,使其成为在步骤2创建的变换

  • Apple提供了一个wwdc示例应用程序“”,附带talk 228:“演示控制器内部的外观”。它有两个自定义演示,其中一个演示设置了演示视图控制器的大小。代码内部的外观应该可以帮助您;)

    正如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);
    
    这将根据确定的比例定位传入视图,然后同时执行两个变换,以便视图缩放并移动到最终位置和大小

    那你就开始吧

    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);
    
    }

    不要忘记将单元格的rect变换为全局坐标空间,这样开始帧对于整个窗口是正确的,而不仅仅是单元格在表格中的位置

    CGRect cellRect=[_tableView rectForRowAtIndexPath:[_tableView indexPathForSelectedRow]];
    
    cellRect=[self.tableView convertRect:cellRect toView:presenting.view];
    

    希望这有帮助!

    谢谢你的回答。我以前没有使用过CGAffineTransform,但它听起来会随着时间的推移(比如,从其大小的50%扩展到全尺寸)。就像一个小r