2

Google Now カードが有効になっているときの iOS 用 Google アプリのレイアウトに似た、一連のカードをテーブル ビューに表示するアプリを作成しています。ユーザーがカードをタップすると、新しいビュー コントローラーへのカスタム トランジションが発生するはずです。これは、基本的にカードが大きくなり、ほとんど画面いっぱいになり、詳細が表示されます。カスタム トランジション自体は、カードが上向きにアニメーション化され、カードを保持する新しいビュー コントローラーである最終的なサイズと位置に達するまでサイズが大きくなるように見えるはずです。

カスタムView Controllerトランジションを使用してこれにアプローチしようとしています。カードがタップされると、カスタム ビュー コントローラー トランジションを で開始し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;
}

私が見つけているのは、新しいビューがアニメーションの開始直後に最終的なサイズに自動的に設定されていることです。その後、アニメーションは上向きにアニメーション化された新しいビューです。UIPresentationController のドキュメントによると、ブレークポイントを使用frameOfPresentedViewInContainerViewして、呼び出し中に呼び出されていることに気付きました[transitionContext.containerView addSubview:toView]。これは、おそらくこれが起こっている理由を説明しています。「アニメーションの最後に提示されたビューに割り当てるフレーム四角形」を返しますframeOfPresentedViewInContainerView

ただし、どのように進めるか、またはそれが本当に可能かどうかはわかりません。私が見たカスタム ビュー コントローラー遷移のすべての例では、提示されたビュー コントローラーの最終的なサイズはすべて静的で、アニメーション中は変化しませんでした。アニメーション中に提示されたビューのサイズを変更してカスタム ビュー コントローラーの遷移を実行する方法はありますか、または別の方法でこれにアプローチする必要がありますか?

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 に答える
0

Apple は wwdc サンプル アプリ ' LookInside ' を提供しており、トーク 228: 'A look inside presentation controllers' に付随しています。2 つのカスタム プレゼンテーションを備えており、そのうちの 1 つは表示されたビュー コントローラーのサイズをアニメーション化します。そのコードの中を見ると、助けになるはずです;)

于 2014-09-04T12:05:47.527 に答える