UIView垂直翻转动画

Posted

技术标签:

【中文标题】UIView垂直翻转动画【英文标题】:UIView vertical flip animation 【发布时间】:2011-03-22 14:14:16 【问题描述】:

我有一个带有UIViewAnimationTransitionFlipFromRightios UIView。我需要它垂直翻转。页面卷曲过渡不会削减它。我认为这需要一些定制的东西。

有什么想法吗?

【问题讨论】:

【参考方案1】:

只需使用 Core Animation Transforms 编写您自己的翻转方法。

- (void)verticalFlip
    [UIView animateWithDuration:someDuration delay:someDelay animations:^
        yourView.layer.transform = CATransform3DMakeRotation(M_PI,1.0,0.0,0.0);
     completion:^
        // code to be executed when flip is completed
    ];

确保您已添加和包含核心动画库/框架,如果您想使用 M_PI 表示法,还包含 math.h

编辑:

要让它在中途翻转时从本质上“改变”视图,请执行以下操作:

- (void)verticalFlip
    [UIView animateWithDuration:someDuration delay:someDelay animations:^
        yourView.layer.transform = CATransform3DMakeRotation(M_PI_2,1.0,0.0,0.0); //flip halfway
     completion:^
        while ([yourView.subviews count] > 0)
            [[yourView.subviews lastObject] removeFromSuperview]; // remove all subviews
        // Add your new views here 
        [UIView animateWithDuration:someDuration delay:someDelay animations:^
            yourView.layer.transform = CATransform3DMakeRotation(M_PI,1.0,0.0,0.0); //finish the flip
         completion:^
            // Flip completion code here
        ];
    ];

这也可以:

- (void)verticalFlip

    // Do the first half of the flip
    [UIView animateWithDuration:someDuration delay:someDelay animations:^
        yourView.layer.transform = CATransform3DMakeRotation(M_PI_2,1.0,0.0,0.0); //flip halfway
     completion:^
        while ([yourView.subviews count] > 0)
            [[yourView.subviews lastObject] removeFromSuperview]; // remove all subviews
        // Add your new views here 
    ];

    // After a delay equal to the duration+delay of the first half of the flip, complete the flip
    [UIView animateWithDuration:someDuration delay:durationOfFirstAnimation animations:^
        yourView.layer.transform = CATransform3DMakeRotation(M_PI,1.0,0.0,0.0); //finish the flip
     completion:^
        // Flip completion code here
    ];

干杯。

【讨论】:

我已经让视图翻转,但我需要以某种方式显示视图的“背面”。有没有办法在这个动画中隐藏它的子视图,所以它模拟视图在背面是“空的”? 对于 3D 变换,您需要使用 yourView.layer.transform 而不是 yourView.transform 完成块应该有一个布尔值。完成:^(布尔完成) 你也应该使用 call + (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:( void (^)(BOOL finished)) 在“EDIT:”标记后的代码中完成 - 选项:原始注释中缺少参数 您应该在 2 * M_PI 上旋转,以免在秒代码块中翻转的后半部分颠倒查看【参考方案2】:

从 iOS 5.0 开始,无需编写自己的核心动画转换来进行垂直翻转。只需使用 UIKit 的 UIViewAnimationOptionTransitionFlipFromTop and UIViewAnimationOptionTransitionFlipFromBottom 转换,所有这些东西都变成了一个方法调用。

这些行为类似于 UIViewAnimationOptionTransitionFlipFromLeftUIViewAnimationOptionTransitionFlipFromRight(自 iOS 2.0 以来一直存在)。

示例用法:

[UIView transitionFromView:viewToReplace
                    toView:replacementView
                  duration:1
                   options:UIViewAnimationOptionTransitionFlipFromBottom
                completion:nil];

上面的代码会垂直翻转viewToReplace的superview。在动画的中途,当superview垂直于屏幕,不可见的瞬间,viewToReplacereplacementView替换。

就这么简单。

【讨论】:

注意:在调用动画之前将两个视图插入到它们的父视图中。 “viewToReplace”必须在“replacementView”之前。两个视图都必须设置为 hidden=false。 @Artjom 你所声称的与我的经历不同。这对我来说非常有效,无需在调用transitionFromView:... 之前将replacementView 插入超级视图。也许还有其他一些不明显相关的事情,我们也在做不同的事情,导致我们观察到的不同?您能否提供一个示例项目来展示您所描述的内容? 在我的例子中,两个视图都是从 nib 作为类成员初始化的。但是如果不将两者都插入到翻转的超级视图中,您的方法将不起作用。 只需将视图设置为属性,然后只插入一个视图,然后翻转处理替换【参考方案3】:

Brenton 的代码对我不起作用,所以我对苹果文档和found this piece of code 进行了更多挖掘以进行水平翻转:

- (IBAction)toggleMainViews:(id)sender 
    [UIView transitionFromView:(displayingPrimary ? primaryView : secondaryView)
                        toView:(displayingPrimary ? secondaryView : primaryView)
                      duration:1.0
                       options:(displayingPrimary ? 
                                    UIViewAnimationOptionTransitionFlipFromRight :
                                    UIViewAnimationOptionTransitionFlipFromLeft)
                    completion:^(BOOL finished) 
                                   if (finished) 
                                       displayingPrimary = !displayingPrimary;
                                   
                              
    ];

您可以通过将选项从UIViewAnimationOptionTransitionFlipFromRight : UIViewAnimationOptionTransitionFlipFromLeft 更改为UIViewAnimationOptionTransitionFlipFromTop : UIViewAnimationOptionTransitionFlipFromBottom 来进行垂直翻转。

工作就像一个魅力。

【讨论】:

这不是垂直翻转。它的系统提供水平翻转 反对票是怎么回事?此代码比其他示例更短且更清晰。有没有隐藏的陷阱? 一定有人投了反对票 b/c 原来的问题是关于垂直翻转,而不是水平翻转。水平的比 Apple 提供的 UIViewAnimationOptionTransition 常量更容易。因此,提问者关于垂直过渡效果的原始查询。 您可以通过将选项从....options:isDetailTileView ? UIViewAnimationOptionTransitionFlipFromRight : UIViewAnimationOptionTransitionFlipFromLeft)更改为....options:isDetailTileView ? UIViewAnimationOptionTransitionFlipFromTop : UIViewAnimationOptionTransitionFlipFromBottom)来进行垂直翻转 还有一件事。如果您尝试翻转子视图并且不希望父视图翻转。将您的两个子视图放在容器视图中。然后它不会翻转你的全屏视图!【参考方案4】:

UIViewAnimationOptionTransitionFlipFromTop 很容易使用,但我们无法使用 UIViewAnimationOptionTransitionFlipFromTop 创建交互式过渡。我们需要更改图层的变换来创建交互式过渡。

仅仅使用 CATransform3DMakeRotation 创建一个变换是不够的,没有光效,没有透视。我写了一个示例来添加这些效果。您可以轻松地将其更改为交互式过渡。

演示:

示例代码:

CALayer *sideALayer = sideAView.layer;
CALayer *sideBLayer = sideBView.layer;
CALayer *containerLayer = containerView.layer;

sideALayer.opacity = 1;
sideBLayer.opacity = 0;
sideBLayer.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);
containerLayer.transform = CATransform3DIdentity;

CATransform3D perspectiveTransform = CATransform3DIdentity;
perspectiveTransform.m34 = -1.0 / containerViewWidth;
[UIView animateKeyframesWithDuration:1 delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^

    [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0.5 animations:^
        sideALayer.opacity = 0;
        containerLayer.transform = CATransform3DConcat(perspectiveTransform,CATransform3DMakeRotation(M_PI_2, 0, 1, 0));
    ];
    [UIView addKeyframeWithRelativeStartTime:0.5 relativeDuration:0.5 animations:^
        sideBLayer.opacity = 1;
        containerLayer.transform = CATransform3DConcat(perspectiveTransform, CATransform3DMakeRotation(M_PI, 0, 1, 0));
    ];
 completion:nil];

sideAView 和 sideBView 是 containerView 的子视图。

containerView 设置为黑色背景。

【讨论】:

这个动画有问题。如您所见,在旋转的后半部分,透视被完全移除,看起来很奇怪。【参考方案5】:

Swift 4.0 版本 100% 工作解决方案

// view1: represents view which should be hidden and from which we are starting
// view2: represents view which is second view or behind of view1
// isReverse: default if false, but if we need reverse animation we pass true and it
// will Flip from Left

func flipTransition (with view1: UIView, view2: UIView, isReverse: Bool = false) 
    var transitionOptions = UIViewAnimationOptions()
    transitionOptions = isReverse ? [.transitionFlipFromLeft] : [.transitionFlipFromRight] // options for transition

    // animation durations are equal so while first will finish, second will start
    // below example could be done also using completion block.

    UIView.transition(with: view1, duration: 1.5, options: transitionOptions, animations: 
        view1.isHidden = true
    )

    UIView.transition(with: view2, duration: 1.5, options: transitionOptions, animations: 
        view2.isHidden = false
    )

函数的调用:

anim.flipTransition(with: viewOne, view2: viewTwo)
anim.flipTransition(with: viewTwo, view2: viewOne, isReverse: true)

最佳实践是创建UIView 扩展并将此函数保存到该扩展中,以便任何UIView 子对象都可以访问它。此解决方案也可以使用 completionBlock 编写。

【讨论】:

感谢@C0mrade,您节省了我的时间。 有没有办法摆脱翻转时发生的视图变暗?【参考方案6】:

要翻转到 UIView:

  -(void) goToSeconVC
 
  SecondVC *secondVCObj = [[SecondVC alloc] init];
  [UIView beginAnimation: @”View Flip” context: nil];
  [UIView setAnimationDuration: 1.0];
  [UIView setAnimationCurve: UIViewAnimationCurveEaseInOut];
  [UIView setAnimationTransition: UIViewAnimationTransitionFlipFromRight forView: self.navigationController.view cache: NO];
  [sef.navigationController pushViewController: seconVCObj animated: YES];
  [UIView commitAnimation];
 
**To flip into a view controller:**
          viewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
         [self presentViewController:viewController animated:YES completion:nil];
**To flip out of it:**

[self dismissViewControllerAnimated:YES completion:nil];

【讨论】:

【参考方案7】:

@C0mrade 的 Swift 5 版本

func flipTransition (with view1: UIView, view2: UIView, isReverse: Bool = false) 
    var transitionOptions = UIView.AnimationOptions()
    transitionOptions = isReverse ? [.transitionFlipFromLeft] : [.transitionFlipFromRight]

    UIView.transition(with: view1, duration: 1.5, options: transitionOptions, animations: 
        view1.isHidden = true
    )

    UIView.transition(with: view2, duration: 1.5, options: transitionOptions, animations: 
        view2.isHidden = false
    )

【讨论】:

我用过这段代码,但是看起来不太流畅。我期望的是,在动画隐藏第一个视图的过程中,将被隐藏。目前在开头是隐藏的。【参考方案8】:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.75];
// checks to see if the view is attached
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight
                       forView:flipLabel
                         cache:YES];

 flipLabel.backgroundColor = [UIColor yellowColor];



[UIView commitAnimations];

你可以在翻转视图时进行任何你想要的修改,这里我改变了背景颜色

【讨论】:

-1 因为 a)这是一个水平翻转,并且 b)我认为这不会增加我的答案尚未提供的任何新内容。

以上是关于UIView垂直翻转动画的主要内容,如果未能解决你的问题,请参考以下文章

UIView 翻转动画没有动画

uiview上的按钮翻转动画超出框架

仅翻转动画 UIVIEW

如何使用 UIView 创建自定义翻转动画

如何在 Swift 中多次为 UIView 的翻转设置动画

如何在 iOS 中为两个 UIView 翻转设置动画?