如何在更改UIView的隐藏模式时添加动画?

51

我想在更改视图的隐藏模式时添加动画效果,即

my_view.hidden=YES;

我在导航栏中添加了一个按钮。当我们点击它时,新视图将被设置为非隐藏状态。它绘制在导航表的上方。


你想要什么样的动画效果,例如淡入淡出、翻转等? - Erik B
苹果声称多年来.isHidden是可动画化的,但这完全是荒谬的,因为它实际上并不能。 - Fattie
12个回答

61

将视图的不透明度从100%动画到0%。在动画完成时,回调函数将视图设置为隐藏。您可能还希望在回调函数中将不透明度重置为100%,以便在取消隐藏后视图将完全不透明显示。

yourView.alpha = 0.0 //for zero opacity
yourView.alpha = 1.0 //for 100% opacity

1
为什么要隐藏,如果我们需要在此之前使用alpha?使用alpha会有性能惩罚,我们不能通过这种方法来避免它。 - Reckoner

36

然而,隐藏没有动画效果;您可以使用下面的 Swift 代码获得相同的结果:

UIView.animate(withDuration: 0.2, delay: 0, options: [], animations: {            
    self.yourView.alpha = 0 // Here you can change the alpha property of the view 
}, completion: { _ in  
    self.yourView.isHidden = true // Here you hide it when animation done
})

太棒了,简单易懂。谢谢! - Mike Taverne
1
出现错误:nil与预期的参数类型“UIViewAnimationOptions”不兼容。我正在使用Xcode 7.3.1。 - Jayprakash Dubey
1
@JayprakashDubey,您可以将“ options: nil”替换为“ options:[]”。 - chengsam
这可能是最佳答案(实际上,在 Obj-C 时代可能不是),它简洁明了且正是 OP/我所需的。 - Tommy K

31

很遗憾,hidden不是可以通过UIView动画实现动画效果的属性。我认为你最好的选择可能是使用@Erik B建议的其中一种动画,或者开始尝试使用Core Animations,它们更加强大。查看UIView动画和核心动画的文档可能会有所帮助。

我通过使用UIView动画从下方滑出新视图来实现了类似您建议的功能。这样做使它看起来像一个抽屉滑出。如果你想要做类似这样的事情,你需要拦截touch up inside事件并在那里放置动画代码。

- (IBAction)buttonClicked:(id)sender {
    [UIView animateWithDuration:0.5
                          delay:0.0 
                        options:UIViewAnimationCurveEaseOut
                     animations:^(void) {
                        self.myView.frame = /* set the frame here */
                     } 
                     completion:NULL];
}

2
选项应为:UIViewAnimationOptionCurveEaseInOut - inix

24

我认为更合适的方法是:

[UIView transitionWithView:aView
                  duration:0.3
                   options:UIViewAnimationOptionTransitionCrossDissolve 
                animations:^(void){
                              aView.hidden = NO;
                           }
                completion:nil];

7
这是正确答案,不需要改动α值。我已经整理过它,使其更易读。 - malhal

20

更新至Swift 3:

UIView.animate(withDuration: 0.2, delay: 0.2, options: .curveEaseOut,
      animations: {firstView.alpha = 0}, 
      completion: { _ in firstView.isHidden = true
        //Do anything else that depends on this animation ending
    })

如果您希望在首次查看后将某些内容重新动画化,则可以在完成块中复制代码,并使用 alpha = 1hidden = false


18

这是我写的一个类别,介绍了UIView上的一个新的“hidden”属性,可以正确地支持动画:

这是我为介绍UIView上的新“hidden”属性所编写的类别,它可以正确支持动画。

@implementation UIView (AnimateHidden)

-(void)setHiddenAnimated:(BOOL)hide
{
  [UIView animateWithDuration:0.5
                        delay:0.0
                      options: UIViewAnimationCurveEaseOut
                   animations:^
                             {
                           [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
                           if (hide)
                             self.alpha=0;
                           else
                           {
                             self.hidden= NO;
                             self.alpha=1;
                           }
                         }
      completion:^(BOOL b)
      {
        if (hide)
          self.hidden= YES;
      }
  ];
}
@end

谢谢,这个对我有用!但我加了一些内容以使其与“hidden”属性互操作:基本上,在最后始终将“alpha”保留为1.0,设置正确的起始“alpha”和“hidden”。 - meaning-matters

9

以下是修正后的 N.J. 版本:

@implementation UIView (AnimateHidden)

-(void)setHiddenAnimated:(BOOL)hide duration:(NSTimeInterval)duration {
    if(self.hidden == hide)
        return;
    if(hide)
        self.alpha = 1;
    else {
        self.alpha = 0;
        self.hidden = NO;
    }
    [UIView animateWithDuration:duration animations:^{
        if (hide)
            self.alpha = 0;
        else
            self.alpha = 1;
    } completion:^(BOOL finished) {
        if(finished)
            self.hidden = hide;
    }];
}

@end

7
这里是相关的Swift版本:
Swift 2
UIView.animateWithDuration(0.5, delay: 0.2, options: UIViewAnimationOptions.CurveEaseOut, animations: {
    objView.alpha = 0
}, completion: { finished in
    objView.hidden = true
})

Swift 3, 4, 5

UIView.animate(withDuration: 0.5, delay: 0.2, options: UIView.AnimationOptions.curveEaseOut, animations: {
    objView.alpha = 0
}, completion: { finished in
    objView.isHidden = true
})

这将执行5秒的动画,并在2秒延迟后执行。

可用的AnimationOptions如下:

CurveEaseInOut, CurveEaseIn, CurveEaseOut, CurveLinear

4

由于一些答案有点混乱,我想我可以发布这个API的极简主义设计。我还添加了延迟和持续时间 - 因为为什么不这样做呢。

实现中,我们有:

#import "UIView+AnimateHidden.h"

@implementation UIView (AnimateHidden)

- (void)setHiddenAnimated:(BOOL)hide
                    delay:(NSTimeInterval)delay
                 duration:(NSTimeInterval)duration {
    [UIView animateWithDuration:duration
                          delay:delay
                        options:UIViewAnimationOptionAllowAnimatedContent
                     animations:^{
                         if (hide) {
                             self.alpha = 0;
                         } else {
                             self.alpha = 0;
                             self.hidden = NO; // We need this to see the animation 0 -> 1
                             self.alpha = 1;
                         }
    } completion:^(BOOL finished) {
        self.hidden = hide;
    }];
}

@end

在头文件中,我们有以下内容。
#import <UIKit/UIKit.h>

@interface UIView (AnimateHidden)

- (void)setHiddenAnimated:(BOOL)hide
                    delay:(NSTimeInterval)delay
                 duration:(NSTimeInterval)duration;

@end

3

NJ 和 Stanislav 在这里的回答帮助我为此创建了一个新类别,我认为这比他们的回答更好,所以我想发布一下我的成果,以便帮助其他人。

请注意,它仅适用于 iOS4 或更高版本,因为它使用了 blocks。

UIView+AnimateHidden.m

#import "UIView+AnimateHidden.h"

@implementation UIView (AnimateHidden)

- (void)setHidden:(BOOL)hidden animated:(BOOL)animated
{
    // If the hidden value is already set, do nothing
    if (hidden == self.hidden) {
        return;
    }
    // If no animation requested, do the normal setHidden method
    else if (animated == NO) {
        [self setHidden:hidden];
        return;
    }
    else {
        // Store the view's current alpha value
        CGFloat origAlpha = self.alpha;

        // If we're unhiding the view, make it invisible initially
        if (hidden == NO) {
            self.alpha = 0;
        }

        // Unhide the view so we can see the animation
        self.hidden = NO;

        // Do the animation
        [UIView animateWithDuration:0.5
                              delay:0.0
                            options: UIViewAnimationOptionCurveEaseOut
                         animations:^{
            // Start animation block
            if (hidden == YES) {
                self.alpha = 0;
            }
            else {
                self.alpha = origAlpha;
            }
            // End animation block
        }
                        completion:^(BOOL b){
            // Start completion block
            // Finish up by hiding the view if necessary...
            self.hidden = hidden;
            // ... and putting back the correct alpha value
            self.alpha = origAlpha;
            // End completion block
        }];
    }
}

@end

请参考Abhi的答案,使用新的API可以使这个过程变得更加简单,无需涉及alpha值。 - malhal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接