2

我正在编写一个在表格视图中包含一系列卡片的应用程序,类似于启用 Google Now 卡片时适用于 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根据 UIPresentationController 文档返回“在动画结束时分配给呈现视图的框架矩形”。

但是,我不确定如何进行,或者是否真的有可能。我见过的所有自定义视图控制器转换的示例都具有呈现的视图控制器的最终大小,并且在动画期间保持不变。有没有办法在动画期间通过改变呈现视图的大小来执行自定义视图控制器转换,还是我必须以不同的方式处理这个?

4

3 回答 3

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

这会考虑到确定的比例来定位传入视图,然后同时执行两个变换,以便视图缩放并移动到最终位置和大小。

然后你就设置

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];

希望这可以帮助!

于 2014-10-23T13:09:16.587 回答
1

基本上你需要做的是在你的转换委托中使用CGAffineTransform为你的 toView.transform 设置动画。要做的步骤:

  1. 在动画之前设置你的 toView.frame = 你的框架,当它没有显示时
  2. 比方说,创建 CGAffineTransformMakeScale 以从隐藏帧缩放到您想要的最终呈现帧
  3. 在动画块上设置为 View.transform 到您在步骤 2 中创建的变换
于 2014-09-02T15:58:40.640 回答
0

Apple 提供了一个 wwdc 示例应用程序“ LookInside ”,伴随着谈话 228:“A look inside presentation controllers”。它具有 2 个自定义演示文稿,其中一个动画呈现的视图控制器的大小。看看里面的代码应该可以帮助你;)

于 2014-09-04T12:05:47.527 回答