我正在尝试使用Core Animation重新创建Apple的UIView transitionFromView:ToView:
,以便我可以将其用于交互式视图控制器转换。它几乎就在那里,但我无法让“到”视图控制器的视图显示在卡的背面。
CATransform3D inRotation = CATransform3DMakeRotation(M_PI, 0.0, 1.0, 0.0);
inRotation.m34 = -0.02;
CATransform3D outRotation = CATransform3DMakeRotation(-0.01, 0.0, 1.0, 0.0);
outRotation.m34 = -0.02;
[UIView animateKeyframesWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:0 animations:^{
[UIView addKeyframeWithRelativeStartTime:0.0
relativeDuration:0.5
animations:^{
fromViewController.view.layer.transform = inRotation;
}];
[UIView addKeyframeWithRelativeStartTime:0.5
relativeDuration:0.5
animations:^{
toViewController.view.layer.transform = outRotation;
}];
} completion:^(BOOL finished) {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
我认为我需要在转换的中途以某种方式交换两个视图(fromViewController.view
和toViewController.view
),但我似乎无法在任何地方找到解决方案。
答案 0 :(得分:1)
我不确定这是否是最常用的方法,但我有一个有效的解决方案:
[fromViewController.view.layer setDoubleSided:NO];
[toViewController.view.layer setDoubleSided:NO];
[container insertSubview:toViewController.view belowSubview:fromViewController.view];
CGFloat h = 0.0001;
CATransform3D initialToRotation = CATransform3DMakeRotation(M_PI - h, 0.0, 1.0, 0.0);
initialToRotation.m34 = -0.002;
[toViewController.view.layer setTransform:initialToRotation];
CATransform3D initialFromRotation = CATransform3DIdentity;
initialFromRotation.m34 = -0.002;
[fromViewController.view.layer setTransform:initialFromRotation];
[UIView animateWithDuration:0.5 animations:^{
[fromViewController.view.layer setTransform:CATransform3DRotate(initialFromRotation, M_PI - h, 0.0, 1.0, 0.0)];
[toViewController.view.layer setTransform:CATransform3DRotate(initialToRotation, M_PI + h, 0.0, 1.0, 0.0)];
} completion:^(BOOL finished) {
BOOL wasCanceled = [transitionContext transitionWasCancelled];
if (wasCanceled) {
[transitionContext completeTransition:NO];
} else {
[transitionContext completeTransition:YES];
}
}];
重要的是前后两者需要一起旋转,前部需要在过渡之前旋转。您可以在容器视图中设置视图层次结构,但在viewControllers'上调用转换代码。直接观点。此外,CoreAnimation似乎没有任何顺时针或逆时针的概念,因此您需要按 over 或 pi弧度的顺序旋转确保正确的行为。
答案 1 :(得分:0)
我有一个项目可以做到这一点。这是我们用于这个项目的内容。它不是CoreAnimation,但可以完成工作。
-(void)configureView{
UITapGestureRecognizer *singleFingerTap =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleSingleTap:)];
_contentsView = [[UIView alloc] initWithFrame:CGRectInset(self.view.bounds, 0, 0)];
_contentsView.backgroundColor = RGB(GRAY_BACKGROUND);
_contentsView.layer.cornerRadius = 0;
_contentsView.layer.masksToBounds = YES;
[_contentsView.layer setBorderColor: [RGB(DARK_GRAY) CGColor]];
[_contentsView.layer setBorderWidth: .5];
[_contentsView addGestureRecognizer:singleFingerTap];
[self.view addSubview:_contentsView];
CardFrontController *front = [CardFrontController new];
[front.view setFrame:CGRectMake(0, 0, 300, 300)];
[_contentsView addSubview:front.view];
_backView = [[UIView alloc] initWithFrame:CGRectInset(self.view.bounds, 0, 0)];
// load the back of the card
cardBack = [CardBackController new];
[_backView addSubview:cardBack.view];
}
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {
// animate the card flipping
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
if (!_review) {
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.view cache:YES];
} else {
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:YES];
}
[UIView commitAnimations];
// now stuff that we don't need to animate
if (!_review) {
[_contentsView removeFromSuperview];
[self.view addSubview:_backView];
}
else {
[_backView removeFromSuperview];
[self.view addSubview:_contentsView];
}
_review = !_review;
}
答案 2 :(得分:0)
您的inRotation
应该与M_PI_2
(或-M_PI_2
)代替M_PI
。以下解决方案更接近您的原始代码,它通过执行两个四分之一轮换避免了刚刚超过pi或的hacky解决方法:
func flip(_ flipToFront: Bool) {
let fromView: UIView = flipToFront ? toViewController.view! : fromViewController.view!
let toView: UIView = flipToFront ? fromViewController.view! : toViewController.view!
fromView.superview!.insertSubview(fromView, belowSubview: toView)
var initialToRotation: CATransform3D = CATransform3DMakeRotation(.pi, 0, 1, 0)
initialToRotation.m34 = -0.004
toView.layer.transform = initialToRotation
var initialFromRotation: CATransform3D = CATransform3DIdentity
initialFromRotation.m34 = -0.004
fromView.layer.transform = initialFromRotation
UIView.animateKeyframes(withDuration: 0.5, delay: 0, options: .calculationModeLinear, animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5, animations: {
fromView.layer.transform = CATransform3DRotate(initialFromRotation, .pi / (flipToFront ? 2 : -2), 0, 1, 0)
toView.layer.transform = CATransform3DRotate(initialToRotation, .pi / (flipToFront ? -2 : 2), 0, 1, 0)
})
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5, animations: {
fromView.layer.transform = CATransform3DRotate(initialFromRotation, .pi, 0, 1, 0)
toView.layer.transform = CATransform3DRotate(initialToRotation, .pi, 0, 1, 0)
})
}, completion: nil)
}
我之前设定的地方:
override func viewDidLoad() {
super.viewDidLoad()
fromViewController.view.layer.isDoubleSided = false
toViewController.view.layer.isDoubleSided = false
}