简体   繁体   English

UIView.animateWithDuration 不动画 Swift(再次)

[英]UIView.animateWithDuration Not Animating Swift (again)

Note: I've already checked the following stack overflow issues:注意:我已经检查了以下堆栈溢出问题:

27907570 , 32229252 , 26118141 , 31604300 27907570322292522611814131604300

All I am trying to do is fade animate in a view (by alpha) when called by an IBAction attached to a button.当被附加到按钮的 IBAction 调用时,我想要做的就是在视图中淡入淡出动画(通过 alpha)。 Then reverse when a button on the view is hit.然后在点击视图上的按钮时反转。

My wrinkle may be that I'm using a secondary view that is on the ViewDock in the storyboard View.我的问题可能是我正在使用故事板视图中 ViewDock 上的辅助视图。 The view is added to the subview at the time of viewDidLoad where the frame/bounds are set to the same as the superview (for a full layover)视图在 viewDidLoad 时添加到子视图,其中框架/边界设置为与超级视图相同(对于完整停留)

The reason this is done as an overlay view since it is a tutorial indicator.这是作为一个覆盖视图完成的原因,因为它是一个教程指示器。

The result (like many others who've listed this problem) is that the view (and contained controls) simply appears instantly and disappears as instantly.结果(与列出此问题的许多其他人一样)是视图(和包含的控件)只是立即出现并立即消失。 No fade.没有褪色。

I have tried animationWithDuration with delay, with and without completion, with transition, and even started with the old UIView.beginAnimations.我尝试过带延迟、带完成和不带完成、带过渡的 animationWithDuration,甚至从旧的 UIView.beginAnimations 开始。

Nothing is working.没有任何工作。 Suggestions warmly welcomed.热烈欢迎建议。

The code is about as straight forward as I can make it:该代码与我所能做到的一样简单:
Edit: Expanded the code to everything relevant编辑:将代码扩展到所有相关内容
Edit2: TL;DR Everything works with the exception of UIViewAnimateWithDuration which seems to ignore the block and duration and just run the code inline as an immediate UI change. Edit2: TL;DR 除了 UIViewAnimateWithDuration 之外,一切都可以正常工作,它似乎忽略了块和持续时间,而只是将代码作为即时 UI 更改内联运行。 Solving this gets the bounty解决这个问题得到赏金

@IBOutlet var infoDetailView: UIView! // Connected to the view in the SceneDock

override func viewDidLoad() {
    super.viewDidLoad()

    // Cut other vDL code that isn't relevant

    setupInfoView()
}

func setupInfoView() {
    infoDetailView.alpha = 0.0
    view.addSubview(infoDetailView)
    updateInfoViewRect(infoDetailView.superview!.bounds.size)
}

func updateInfoViewRect(size:CGSize) {
    let viewRect = CGRect(origin: CGPointZero, size: size)

    infoDetailView.frame = viewRect
    infoDetailView.bounds = viewRect

    infoDetailView.layoutIfNeeded()
    infoDetailView.setNeedsDisplay()
}

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
    updateInfoViewRect(size)
}

func hideInfoView() {
    AFLog.enter(thisClass)
    UIView.animateWithDuration(
        2.0,
        animations:
        {
            self.infoDetailView.alpha = 0.0
        },
        completion:
        { (finished) in
            return true
        }
    )
    AFLog.exit(thisClass)
}

func showInfoView() {
    AFLog.enter(thisClass)
    UIView.animateWithDuration(
        2.0,
        animations:
        {
            self.infoDetailView.alpha = 0.75
        },
        completion:
        { (finished) in
            return true
        }
    )
    AFLog.exit(thisClass)
}

// MARK: - IBActions

@IBAction func openInfoView(sender: UIButton) {
    showInfoView()
}

@IBAction func closeInfoView(sender: UIButton) {
    hideInfoView()
}

Please note, I started with the following:请注意,我从以下几点开始:

func showInfoView() {
    UIView.animateWithDuration(2.0, animations: { () -> Void in
        self.infoDetailView.alpha = 0.75
    })
}

func hideInfoView() {
    UIView.animateWithDuration(2.0, animations: { () -> Void in
        self.infoDetailView.alpha = 0.00
    })
}

If you infoDetailView is under auto layout constraints you need to call layoutIfNeeded on the parent view inside animateWithDuration:如果 infoDetailView 处于自动布局约束下,则需要animateWithDuration视图上调用 layoutIfNeeded:

func showInfoView() {
    self.view.layoutIfNeeded() // call it also here to finish pending layout operations
    UIView.animate(withDuration: 2.0, animations: {
        self.infoDetailView.alpha = 0.75
        self.view.layoutIfNeeded()
    })
}

Theoretically this should not be needed if you just change the .alpha value, but maybe this could be the problem in this case.从理论上讲,如果你只是改变了阿尔法值,但也许这可能是在这种情况下,这个问题不应该是必要的。

There are several strange things I can see,我可以看到一些奇怪的东西,

first, remove:首先,删除:

infoDetailView.layoutIfNeeded()
infoDetailView.setNeedsDisplay()

Usually you don't need to call those methods manually unless you know exactly what you are doing.通常您不需要手动调用这些方法,除非您确切地知道自己在做什么。

Also, when you are changing the size:此外,当您更改大小时:

infoDetailView.frame = viewRect
infoDetailView.bounds = viewRect

You never need to set both bounds and frame .您永远不需要同时设置boundsframe Just set frame .只需设置frame

Also, you should probably make sure that the view actually doesn't ignore the frame by setting:此外,您可能应该通过设置来确保视图实际上不会忽略框架:

infoDetailView.translatesAutoresizingMaskIntoConstraints = true

Instead of resetting the frame, just set autoresize mask:而不是重置框架,只需设置自动调整大小掩码:

infoDetailView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]

Resulting in:导致:

override func viewDidLoad() {
    super.viewDidLoad()

    // Cut other vDL code that isn't relevant

    setupInfoView()
}

func setupInfoView() {
    infoDetailView.alpha = 0.0
    infoDetailView.translatesAutoresizingMaskIntoConstraints = true
    infoDetailView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
    infoDetailView.frame = view.bounds
    view.addSubview(infoDetailView)
}

func hideInfoView() {
  ...
}

I think this should actually help because immediate animations are often connected to size problems.我认为这实际上应该会有所帮助,因为即时动画通常与尺寸问题有关。

If the problem persists, you should check whether the infoDetailView in your animation is the same object as the infoDetailView you are adding to the controller.如果问题仍然存在,您应该检查动画中的infoDetailView是否与您添加到控制器的infoDetailView是同一个对象。

For others looking to start an animation immediately when a view loads...对于希望在视图加载时立即开始动画的其他人...

The animation won't work if you call UIView.animate(...) inside viewDidLoad .如果您在viewDidLoad调用UIView.animate(...) ,动画将不起作用。 Instead it must be called from the viewDidAppear function.相反,它必须从viewDidAppear函数中调用。

override func viewDidAppear(_ animated: Bool) {
    UIView.animate(withDuration: 3) {
        self.otherView.frame.origin.x += 500
    }
}

If the animation does not seem to execute then consider examining the state of each of your views, before you enter the animation block.如果动画似乎没有执行,那么在进入动画块之前,请考虑检查每个视图的状态。 For example, if the alpha is already set to 0.4 then the animation that adjusts your view alpha, will complete almost instantly, with no apparent effect.例如,如果 alpha 已经设置为 0.4,那么调整视图 alpha 的动画将几乎立即完成,没有明显效果。

Consider using a keyframe animation instead.考虑改用关键帧动画。 This is what a shake animation in objective c looks like.这就是目标 c 中的抖动动画的样子。

+(CAKeyframeAnimation*)shakeAnimation {
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
    animation.values = @[[NSValue valueWithCATransform3D:CATransform3DMakeTranslation(-10.0, 0.0, 0.0)],
                         [NSValue valueWithCATransform3D:CATransform3DMakeTranslation(10.0, 0.0, 0.0)]];
    animation.autoreverses = YES;
    animation.repeatCount = 2;
    animation.duration = 0.07;
    return animation;
}

Here is a post that shows you how to adjust alpha with keyframes https://stackoverflow.com/a/18658081/1951992这是一篇文章,向您展示如何使用关键帧调整 alpha https://stackoverflow.com/a/18658081/1951992

Make sure infoDetailView 's opaque is false.确保infoDetailViewopaque为 false。

https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/instp/UIView/opaque https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/instp/UIView/opaque

This property provides a hint to the drawing system as to how it should treat the view.该属性为绘图系统提供了一个关于它应该如何处理视图的提示。 If set to true, the drawing system treats the view as fully opaque, which allows the drawing system to optimize some drawing operations and improve performance.如果设置为 true,绘图系统会将视图视为完全不透明,这允许绘图系统优化某些绘图操作并提高性能。 If set to false, the drawing system composites the view normally with other content.如果设置为 false,绘图系统通常会将视图与其他内容合成。 The default value of this property is true.此属性的默认值为 true。

Use this code:使用此代码:

Swift 2斯威夫特 2

UIView.animateWithDuration(0.3, animations: { () -> Void in
    self.infoDetailView.alpha = 0.0 
})

Swift 3, 4, 5斯威夫特 3、4、5

UIView.animate(withDuration: 0.3, animations: { () -> Void in
    self.infoDetailView.alpha = 0.0 
})

I've replicated your code and it work well, it's all ok.我已经复制了您的代码并且运行良好,一切正常。 Probably you must control constraints, IBOutlet and IBActions connections.可能您必须控制约束、IBOutlet 和 IBActions 连接。 Try to isolate this code into a new project if it's necessary.如有必要,请尝试将此代码隔离到新项目中。

Update : my code and my storyboard and project folder photo:更新我的代码和我的故事板和项目文件夹照片:

我的故事板和项目文件夹照片

Every object (view and buttons) are with default settings.每个对象(视图和按钮)都具有默认设置。

在此处输入图片说明

I've commented all AFLog lines (probably it's only any more "verbose mode" to help you) , the rest of your code is ok and it do what do you aspected from it, if you press open button the view fade in, and when you tap close button the view fade out.我已经评论了所有 AFLog 行(可能只是更多的“详细模式”可以帮助您),您的其余代码还可以,并且可以执行您从中获得的操作,如果您按下打开按钮,视图会淡入,并且当您点击关闭按钮时,视图会淡出。

PS Not relevant but i'm using xCode 7.3 , a new swift 2.2 project. PS 不相关,但我使用的是 xCode 7.3,这是一个新的 swift 2.2 项目。

Try Below code.试试下面的代码。 Just play with alpha and duration time to perfect it.只需使用 alpha 和持续时间来完善它。

Hide func隐藏功能

func hideInfoView() {
AFLog.enter(thisClass)
UIView.animateWithDuration(
    2.0,
    animations:
    {
        self.infoDetailView.alpha = 0.8
    },
    completion:
    { (finished) in
        UIView.animateWithDuration(
    2.0,
    animations:
    {
        self.infoDetailView.alpha = 0.4
    },
    completion:
    { (finished) in
        self.infoDetailView.alpha = 0.0
    }
)
    }
)
AFLog.exit(thisClass)
}

Show func显示功能

func showInfoView() {
AFLog.enter(thisClass)
UIView.animateWithDuration(
    2.0,
    animations:
    {
        self.infoDetailView.alpha = 0.3
    },
    completion:
    { (finished) in
        UIView.animateWithDuration(
    2.0,
    animations:
    {
        self.infoDetailView.alpha = 0.7
    },
    completion:
    { (finished) in
        self.infoDetailView.alpha = 1.0
    }
)
    }
)
AFLog.exit(thisClass)
}

Have you tried changing your showInfoView() to something more like toggleInfoView ?您是否尝试将showInfoView()更改为更像toggleInfoView

func toggleInfoView() {
    let alpha = CGFloat(infoDetailView.alpha == 0 ? 1 : 0)
    infoDetailView.alpha = alpha       //this is where the toggle happens
}

It says that if your view's alpha is 0, then change it to 1. Else, make it 0.它说如果您的视图的 alpha 为 0,则将其更改为 1。否则,将其设为 0。

If you need that to happen in an animation, try如果您需要在动画中发生这种情况,请尝试

@IBAction func openInfoView(sender: UIButton) {
    UIView.animate(withDuration: 2.0, animations: {
        self.toggleInfoView()           //fade in/out infoDetailView when animating
    })   
}
  • You'll still want to keep that infoDetailView.alpha = 0.0 where you have it, coming from the viewDidLoad .您仍然希望将infoDetailView.alpha = 0.0保留在您拥有它的地方,来自viewDidLoad

For UILabel component try to changes layer's background color instead.对于 UILabel 组件,尝试改为更改图层的背景颜色。

Try this (Tested on Swift 4):试试这个(在 Swift 4 上测试过):

UIView.animate(withDuration: 0.2, animations: { 
    self.dateLabel.layer.backgroundColor = UIColor.red.cgColor;
})

Had a similar issue with animation not being performed.没有执行动画也有类似的问题。

Changed the function call use perform(aSelector: Selector, with: Any?, afterDelay: TimeInterval) in the form of perform(#selector(functionThatDoesAnimationOfAlphaValue), with: nil, afterDelay: 0) and it worked.perform(#selector(functionThatDoesAnimationOfAlphaValue), with: nil, afterDelay: 0)的形式更改了函数调用 use perform(aSelector: Selector, with: Any?, afterDelay: TimeInterval) perform(#selector(functionThatDoesAnimationOfAlphaValue), with: nil, afterDelay: 0)并且它起作用了。 Even with a TimeInterval set to 0.即使将 TimeInterval 设置为 0。

In case someone else comes here wondering for a solution.以防其他人来到这里想寻求解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM