【问题标题】:UIView.animateWithDuration Not Animating Swift (again)UIView.animateWithDuration 不为 Swift 设置动画(再次)
【发布时间】:2016-07-25 23:55:45
【问题描述】:

注意:我已经检查了以下堆栈溢出问题:

27907570322292522611814131604300

我想要做的就是当被附加到按钮的 IBAction 调用时,在视图中淡入淡出动画(通过 alpha)。然后在点击视图上的按钮时反转。

我的问题可能是我正在使用情节提要视图的 ViewDock 上的辅助视图。视图在 viewDidLoad 时添加到子视图中,其中框架/边界设置为与父视图相同(用于完全停留)

这是作为一个覆盖视图完成的原因,因为它是一个教程指示器。

结果(与许多列出此问题的其他人一样)是视图(和包含的控件)只是立即出现并立即消失。不会褪色。

我尝试了带有延迟的animationWithDuration,有完成和没有完成,有过渡,甚至从旧的UIView.beginAnimations开始。

没有任何工作。欢迎提出建议。

代码尽可能直截了当:
编辑:将代码扩展到所有相关内容
Edit2: TL;DR Everything与 UIViewAnimateWithDuration 例外一起工作,它似乎忽略了块和持续时间,只是运行内联代码作为即时 UI 更改。 解决这个问题获得赏金

@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()
}

请注意,我从以下开始:

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
    })
}

【问题讨论】:

  • "viewDidLoad 时视图被添加到子视图中"
  • FWIW,你可以在这里传递 'nil' 作为完成块。即使您确实有块,它们当然也不应该返回任何东西。我很惊讶 Swift 编译器没有将其标记为错误。
  • @GrahamPerks,我在上面添加了所有相关代码。如原始预调整的失败代码所示,我尝试了有无返回。
  • 最后。该视图出现并配置得很好。一切都在它应该在的地方。所有 UI 元素都可以工作,并且旋转会根据约束调整内容。唯一的问题是 alpha 变化不是作为淡入淡出发生的。只是瞬间出现。
  • 您的代码看起来正确。当应用程序的其他地方存在线程问题时,我已经看到了这样的意外 UI 行为。尝试在 UIView.animateWithDuration() 和 self.infoDetailView.alpha =... 上放置一个断点...它们都在线程 1 (com.apple.main-thread) 上执行吗?

标签: ios swift uikit uiviewanimation uiviewanimationtransition


【解决方案1】:

如果您的 infoDetailView 处于自动布局约束下,您需要在 parent 视图 inside 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()
    })
}

理论上,如果您只是更改 .alpha 值,则不需要这样做,但 也许 在这种情况下,这可能是问题所在。

【讨论】:

  • 这是一个关键提示,您必须在超级视图上而不是在相关视图上调用布局!
  • 这对我有用(我正在更改约束常量值)
【解决方案2】:

我可以看到一些奇怪的东西,

首先,删除:

infoDetailView.layoutIfNeeded()
infoDetailView.setNeedsDisplay()

通常您不需要手动调用这些方法,除非您确切知道自己在做什么。

另外,当你改变尺寸时:

infoDetailView.frame = viewRect
infoDetailView.bounds = viewRect

您永远不需要同时设置boundsframe。只需设置frame

另外,您可能应该通过设置确保视图实际上不会忽略框架:

infoDetailView.translatesAutoresizingMaskIntoConstraints = true

无需重置框架,只需设置 autoresize 掩码:

infoDetailView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]

导致:

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() {
  ...
}

我认为这实际上应该有所帮助,因为即时动画通常与尺寸问题有关。

如果问题仍然存在,您应该检查动画中的infoDetailView 是否与您添加到控制器中的infoDetailView 相同。

【讨论】:

  • Sulthan,这很好地简化了代码,但没有影响动画的根本问题。 infoDetailView 仅如上所示声明为情节提要场景的场景停靠栏上的视图的 IBOutlet。停靠视图或情节提要场景是否有任何潜在的 IB 切换可能需要修复?
  • @LordAndrei 您的代码没有其他问题,所以我很确定这是其他地方的其他隐藏问题。有太多的选择。如果您可以在示例项目中重现该问题并为我们分享,那么我们可以为您提供帮助。
【解决方案3】:

对于希望在视图加载后立即开始动画的其他人...

如果您在viewDidLoad 中调用UIView.animate(...),动画将不起作用。相反,它必须从 viewDidAppear 函数中调用。

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

【讨论】:

    【解决方案4】:

    如果动画似乎没有执行,请考虑在进入动画块之前检查每个视图的状态。例如,如果 alpha 已经设置为 0.4,那么调整视图 alpha 的动画将几乎立即完成,没有明显效果。

    考虑改用关键帧动画。这是objective 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;
    }
    

    这里有一篇文章向您展示如何使用关键帧调整 alpha https://stackoverflow.com/a/18658081/1951992

    【讨论】:

      【解决方案5】:

      确保infoDetailViewopaque 为假。

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

      这个属性为绘图系统提供了一个关于它应该如何处理视图的提示。如果设置为 true,绘图系统将视图视为完全不透明,这允许绘图系统优化某些绘图操作并提高性能。如果设置为 false,则绘图系统通常会将视图与其他内容合成。此属性的默认值为 true。

      【讨论】:

        【解决方案6】:

        试试下面的代码。只需使用 alpha 和持续时间来完善它。

        隐藏功能

        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)
        }
        

        显示函数

        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)
        }
        

        【讨论】:

          【解决方案7】:

          我已经复制了您的代码,它运行良好,一切正常。 可能您必须控制约束、IBOutlet 和 IBActions 连接。如有必要,请尝试将此代码隔离到一个新项目中。

          更新my code 以及我的故事板和项目文件夹照片:

          每个对象(视图和按钮)都具有默认设置。

          我已经评论了所有 AFLog 行(可能只是“详细模式”来帮助你),你的代码的其余部分是好的,如果你按下打开按钮,它会按照你的要求做,当您点击关闭按钮时,视图会淡出。

          PS 不相关,但我正在使用 xCode 7.3,一个新的 swift 2.2 项目。

          【讨论】:

          • Alessandro,您制作动画的视图是从情节提要场景顶部的场景停靠栏中拍摄的吗?
          • 绿色背景的视图是“infoDetailView”,添加了一个视图,在我的例子中,一个干净的viewController的中心,和两个按钮......建立所有连接(iboutlet和ibactions),设置自动布局,它的工作原理。
          • 我已经用源代码和故事板更新了我的答案,你可以开始新项目并尝试一下。
          【解决方案8】:

          使用此代码:

          斯威夫特 2

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

          斯威夫特 3、4、5

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

          【讨论】:

          • 这是我在进行更改之前开始的地方。一样的效果。没有褪色只是出现。
          【解决方案9】:

          您是否尝试过将您的 showInfoView() 更改为类似于 toggleInfoView 的内容?

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

          它表示如果您的视图的 alpha 为 0,则将其更改为 1。否则,将其设置为 0。

          如果您需要在动画中发生这种情况,请尝试

          @IBAction func openInfoView(sender: UIButton) {
              UIView.animate(withDuration: 2.0, animations: {
                  self.toggleInfoView()           //fade in/out infoDetailView when animating
              })   
          }
          
          • 您仍然希望将 infoDetailView.alpha = 0.0 保留在您拥有的位置,来自 viewDidLoad

          【讨论】:

            【解决方案10】:

            对于 UILabel 组件,请尝试更改图层的背景颜色。

            试试这个(在 Swift 4 上测试):

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

            【讨论】:

              【解决方案11】:

              没有执行动画也有类似的问题。

              perform(#selector(functionThatDoesAnimationOfAlphaValue), with: nil, afterDelay: 0) 的形式将函数调用使用perform(aSelector: Selector, with: Any?, afterDelay: TimeInterval) 更改为有效。即使 TimeInterval 设置为 0。

              以防其他人来这里寻找解决方案。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-11-24
                • 1970-01-01
                • 2015-11-20
                • 2015-04-21
                • 2015-09-27
                相关资源
                最近更新 更多