为什么我的UI元素在动画/缩小屏幕后没有正确重置?

时间:2017-07-27 22:15:23

标签: ios swift user-interface modal-dialog segue

所以我会尽可能多地提供关于这个项目的信息。以下是与问题相关的故事板部分的图像:

enter image description here

以下是代码的流程:

1)用户玩游戏。这会扰乱显示的表情符号,最终会隐藏右侧的所有表情符号。

2)当某人赢得游戏时,会调用

performSegue(withIdentifier: "ShowWinScreenSegue", sender: self)

将执行红色箭头指向的segue。这个segue是一个模态segue,超过当前内容,交叉溶解。

3)东西继续在这里,然后我尝试回到游戏屏幕,以便用户可以玩另一个游戏。这是我目前的代码

// self.delegate is the GameController that called the segue
// it's set somewhere else in the code so I can call these reset functions
GameController.gs = GameState()
guard let d = self.delegate else {
    return
}
d.resetGameToMatchState()

dismiss(animated: true, completion: {
    print("Modal dismiss completed")
    GameController.gs = GameState()
    self.delegate?.resetGameToMatchState()
})

所以这就是问题所在。您可以看到我必须两次调用delegate?.resetGameToMatchState()才能实际发生任何事情。如果我删除顶部的那个,当我拨打第二个时没有任何反应,反之亦然。令人讨厌的是,用户将会看到一个奇怪的跳转,其中所有的ui从旧状态变为新状态,因为它的更新时间太晚而且很难。

到目前为止我尝试了什么
所以整个问题让我对UI系统的运作方式感到困惑。

我的第一个想法是,该函数可能正在尝试更新UI线程执行得太早的线程中的UI。所以我将整个resetGameToMatchState置于DispatchQueue.main.async电话中。这没有做任何事情。

然后我认为它之前有效,因为当WinScreenSegue被解雇之前(当它是“show”segue时)它正在调用GameController的{​​{1}}。我尝试在dismiss回调中手动调用此函数,但这也不起作用,感觉非常hacky。

现在我被困住了:(任何帮助都会被完全赞赏。即使只是一些信息可以清除UI系统的运作方式。

这是我的resetGameToMatchState():

ViewDidAppear

更新
所以我发现了这一点。当我尝试重置UI时,唯一不起作用的是将右侧表情符号重置为原始位置。我所做的是在应用程序的开头(在viewDidLoad中)我运行这个:

//reset all emoji labels
    func resetGameToMatchState() {
        DispatchQueue.main.async {
            let tier = GameController.gs.tier

            var i = 0
            for emoji in self.currentEmojiLabels! {
                    emoji.frame = self.currentEmojiLabelInitFrames[i]
                    emoji.isHidden = false
                    emoji.transform = CGAffineTransform(scaleX: 1, y: 1);
                    i+=1
            }

            i=0
            for emoji in self.goalEmojiLabels! {
                emoji.frame = self.goalEmojiLabelInitFrames[i]
                emoji.isHidden = false
                emoji.transform = CGAffineTransform(scaleX: 1, y: 1);
                i+=1
            }

            //match state
            for i in 1...4 {
                if GameController.gs.currentEmojis[i] == GameController.gs.goalEmojis[i] {
                    self.currentEmojiLabels?.findByTag(tag: i)?.isHidden = true
                }
            }

            //reset highlight
            let f = self.highlightBarInitFrame
            let currentLabel = self.goalEmojiLabels?.findByTag(tag: tier)
            let newSize = CGRect(x: f.origin.x, y: (currentLabel?.frame.origin.y)!, width: f.width, height: (currentLabel?.frame.height)! )
            self.highlightBarImageView.frame = newSize

            //update taps
            self.updateTapUI()

            //update goal and current emojis to show what the current goal/current selected emoji is
            self.updateGoalEmojiLabels()
            self.updateCurrentEmojiLabels()

        }
    }

这样可以保存原来的位置以便以后使用。我这样做是因为我在将它们隐藏起来之前将它们设置到屏幕的一侧 现在当我想重置他们的位置时,我这样做:

for emoji in currentEmojiLabels! {
    currentEmojiLabelInitFrames.append(emoji.frame)
}

这应该将它们全部设置为原始帧和比例,但它不能正确设置位置。它虽然重置了规模。奇怪的是,我可以在屏幕左侧看到一小部分表情符号,当它们动画时,它们会从左边的远处动画。我想到为什么框架如此关闭......

更新2
所以我尝试将帧重置代码更改为:

var i = 0
for emoji in self.currentEmojiLabels! {
        emoji.frame = self.currentEmojiLabelInitFrames[i]
        emoji.isHidden = false
        emoji.transform = CGAffineTransform(scaleX: 1, y: 1);
        i+=1
 }

我认为应该将它们正确地重置到左上角,但它仍然将它们推向左侧。这应该证明currentEmojiLabelInitFrames不是问题,并且它与我设置它时有关。 可能是约束被重置或搞砸了?

2 个答案:

答案 0 :(得分:0)

当模式GameController被解散时,您的第一个屏幕viewWillAppear应该会收到来自UIKit的WinScreenController回调。

因此,resetGameToMatchState函数可以将属性设置为true,然后现有的resetGameToMatchState可以移入viewWillAppear,首先检查属性是否已设置。< / p>

var resetNeeded: Bool = false

func resetGameToMatchState() {
  resetNeeded = true
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    // reset code here
}

答案 1 :(得分:0)

TLDR;在重置元素的帧之前重置元素的比例,否则它将缩放/定位错误

终于弄明白了。这里有更多背景知识。当表情符号在屏幕上显示动画时,这称为:

UIView.animate(withDuration: 1.5, animations: {
    let newFrame = self.profileButton.frame
    prevLabel?.frame = newFrame
    prevLabel?.transform = CGAffineTransform(scaleX: 0.1, y: 0.1);
})  { (finished) in
    prevLabel?.isHidden = true
}

因此,这会将框架设置在屏幕的左上角,然后将其缩小。我没有意识到的是,当我想重置元素时,我需要在设置帧之前将比例设置回正常。这是新的重置代码:

for emoji in self.currentEmojiLabels! {
    emoji.transform = CGAffineTransform(scaleX: 1, y: 1) //this needs to be first
    emoji.frame = self.currentEmojiLabelInitFrames[i] //this needs to be after the scale
    emoji.isHidden = false
    i+=1
}