【问题标题】:View animating from the incorrect position从错误的位置查看动画
【发布时间】:2019-02-16 19:01:36
【问题描述】:

我正在尝试在我的代码中为封面视图设置动画。本质上,封面从屏幕外向上滑动(关闭)到屏幕上,并且在用户按下按钮后,封面一直向下滑动(打开)到屏幕外。

我将封面视图向上滑动并进入视图的代码运行良好。但是,将封面视图滑下屏幕并移出视图的代码不起作用!盖子向下滑动的起始位置似乎不正确。封面按预期滑下,但起点太高,以至于动画在它应该开始的地方结束。

我有一个正在运行的错误的屏幕记录(显然减慢了动画速度,因此您可以看到我所说的错误的意思)。向下滑动的盖子应该从它向上滑动的原始位置向下滑动。 Link to recording.

谁能发现我的代码哪里出错了?

func showScoresCover() {
    verticalDistance = ScoresCoverView.frame.size.height
    self.ScoresCoverView.frame.origin.y += verticalDistance
    UIView.animate(
        withDuration: 0.5,
        delay: 0.25,
        options: .curveEaseOut,
        animations:
        { self.ScoresCoverView.frame.origin.y -= self.verticalDistance},
        completion:
        { finished in
          print("Score cover closed.")
        })
}

func hideScoresCover() {
    verticalDistance = ScoresCoverView.frame.size.height
    UIView.animate(
        withDuration: 0.5,
        delay: 0.25,
        options: .curveEaseIn,
        animations:
        { self.ScoresCoverView.frame.origin.y += self.verticalDistance},
        completion:
        { finished in
          print("Score cover opened.")
        })
}

编辑

嘿@Nickolans 感谢您在此问题上的帮助。所以......我有一个关于这个查询的奇怪更新。我实现了你的代码,如果我有一个预编程的按钮来触发 showScoreCover 和 hideScoresCover,它就可以工作。事实证明,即使我的原始代码也可以工作,但同样,只有当我有一个预编程的按钮来触发显示/隐藏功能时。

但是,我需要使用一个按钮来触发该功能,我可以在其中以编程方式重新配置按钮的功能。我是如何通过 .addTarget 和一些选择器来实现的,这些选择器会根据用户在游戏中的位置而有所不同。

无论如何,这就是我的代码的样子:

self.continueButton.addTarget(self, action: #selector(self.hideScoresCover), for: UIControlEvents.touchUpInside)
self.continueButton.addTarget(self, action: #selector(self.startTeamB), for: UIControlEvents.touchUpInside)

最初我只使用了一个 .addTarget 并将 hideScoresCover() 包含在 startTeamB 函数中。这导致了封面没有正确隐藏(在屏幕上开始太高)的原始问题。所以我把它分成上面两个.addTargets,这也导致了同样的问题。但是,如果我注释掉上面与 startTeamB 选择器相关的整个 .addTarget 行,并留下与 hideScoresCover 相关的选择器,那么封面就会显示出来并完全隐藏,就像我想要的那样,动画是完美的。这意味着 hideScoresCover() 中的底层代码工作正常,但问题是在按下继续按钮时以某种方式运行 hideScoresCover。

你知道为什么会这样吗?不知何故,只要有两个 addTargets,或者只有一个目标但 hideScoresCover() 包含在 startTeamB() 中, continueButton 目标就会错误地触发。

我很困惑为什么会这样。 startTeamB() 根本不是一个复杂的函数,所以不应该干扰 hideScoresCover()。因此,这使我只能得出结论,当 continueButton 触发 hideScoresCover() 时,除了 startTeamB 作为目标之外,它还是一个单独的目标,或者当 hideScoresCover() 包含在 startTeamB 本身中时。不寻常的是,当唯一的 .addTarget 是调用 hidesScoresCover 的选择器时,它确实可以正常工作?

@objc func startTeamB() {
    self.UpdateTeam() //Just changes the team name
    self.TeamBTimer() //Starts a timer to countdown teamB's remaining time
    self.TeamAIndicator.isHidden = true //Just hides teamA image
    self.TeamBIndicator.isHidden = false //Just shows teamB image
    print("Hintify: ","-----Start Team B.")
}

【问题讨论】:

  • 可能是您添加到 ScoresCoverView 的 y 位置。如果函数多次运行,y 值将不断变化。
  • 嗨@Nickolans!是的,我认为可能是这种情况,因为起始位置似乎完全超出了“verticalDistance”。但是除了将verticalDistance应用于frame.origin.y之外,您如何为框架设置动画?
  • 动画只发生在 UIView.animate() 中,所以取出“self.ScoresCoverView.frame.origin.y += verticalDistance”并将它移动到你的 viewDidLoad 中,这样就不会每次都设置它调用函数。
  • @Nickolans,我不确定我对你的理解是否正确......动画是让框架在 y 轴上向下移动垂直距离在“动画:{}”闭包内UIView.animate()... 如果我把它移到 viewDidLoad,我们在运行 hideScoresCover() 时不会得到任何动画
  • 好的,我已经编辑了我的回复! PS:如果您还有其他问题,请打开一个新问题/线程,不要重复使用相同的问题/线程:)

标签: swift uiview uiviewanimation


【解决方案1】:

我把它带入 Xcode 并自己设置。我认为问题可能在于您如何更改 Y 值,而不是更改原点更改视图层的 y 位置。

以下代码有效,因此您可以接受!确保在第一次开始时将框架更改为您需要的任何内容。

class ViewController: UIViewController {

//Bool to keep track if view is open
var isOpen = false

var verticalDistance: CGFloat = 0
var ScoresCoverView = UIView()
var button = UIButton()

override func viewDidLoad() {

    //Setup Score view
    ScoresCoverView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.width)
    ScoresCoverView.backgroundColor = .blue
    view.addSubview(ScoresCoverView)

    //Set vertical distance
    verticalDistance = ScoresCoverView.frame.height

    //TEST button to test view animations
    button.frame = CGRect(x: 200, y: 500, width: 100, height: 100)
    button.backgroundColor = .purple
    button.addTarget(self, action: #selector(hasBeenFired), for: .touchUpInside)
    self.view.addSubview(button)
}

//When button pressed
@objc func hasBeenFired() {
    if isOpen {
        self.hideScoresCover()
        self.isOpen = false
    } else {
        self.showScoresCover()
        self.isOpen = true
    }
}

//Show
func showScoresCover() {

    self.ScoresCoverView.isHidden = false

    UIView.animate(withDuration: 0.5, delay: 0.25, options: .curveEaseOut, animations: {
        self.ScoresCoverView.layer.position.y -= self.verticalDistance
    }) { (finished) in
        print("Score cover closed.")
    }
}

//Hide
func hideScoresCover() {

    UIView.animate(withDuration: 0.5, delay: 0.25, options: .curveEaseIn, animations: {
        self.ScoresCoverView.layer.position.y += self.verticalDistance
    }) { (finished) in
        self.ScoresCoverView.isHidden = true
        print("Score cover Opened.")
    }
}
}

编辑

如果您想更改按钮的功能,请确保在添加新目标之前删除之前的目标。

例如,如果您想从显示/隐藏切换到teamB 删除显示/隐藏并添加teamB--反之亦然.

当你第一次开始时,添加你的初始目标:

self.continueButton.addTarget(self, action: #selector(self.hideScoresCover), for: UIControlEvents.touchUpInside)

切换到startTeamB:

self.continueButton.removeTarget(self, action: #selector(self.hideScoresCover), for: UIControlEvents.touchUpInside)
self.continueButton.addTarget(self, action: #selector(self.startTeamB), for: UIControlEvents.touchUpInside)

切换到 hideScoreCover:

self.continueButton.removeTarget(self, action: #selector(self.startTeamB), for: UIControlEvents.touchUpInside)
self.continueButton.addTarget(self, action: #selector(self.hideScoresCover), for: UIControlEvents.touchUpInside)

【讨论】:

  • 嗯...奇怪的是,这并不能解决问题。仍然遇到同样的问题
  • 好的,我更新了答案中的代码!该代码有效。我认为这是您更改 Y 的方式,或者可能是您的代码布局方式。无论哪种方式,上面的代码都可以解决问题。
  • 谢谢伙计!它似乎奏效了。当我如上所述使用您的代码时,块按预期移动。当我将它移动到我的代码时,会发生同样的错误,所以我必须有某种冲突的布局问题,这些问题会阻止视图按预期向下滑动......我已经手动重新创建了我的故事板并创建了一个新的 VC以上及其工作。感谢您的帮助
  • 嘿@Nickolans 我已经对我的原始问题添加了一个编辑,希望你能回答。您的代码有效(就像我的原始代码一样),但它被触发的方式似乎是导致问题的原因
【解决方案2】:

我只想说一件事,+= 在这里可能没有必要。

func showScoresCover() {
verticalDistance = ScoresCoverView.frame.size.height
self.ScoresCoverView.frame.origin.y += verticalDistance
UIView.animate(
    withDuration: 0.5,
    delay: 0.25,
    options: .curveEaseOut,
    animations:
    { self.ScoresCoverView.frame.origin.y -= self.verticalDistance},
    completion:
    { finished in
      print("Score cover closed.")
    })
}

应该是

   `self.ScoresCoverView.frame.origin.y = verticalDistance`

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-16
    • 1970-01-01
    • 2018-03-19
    • 2011-06-28
    • 2019-09-23
    • 2017-12-20
    相关资源
    最近更新 更多