所以我会尽可能多地提供关于这个项目的信息。以下是与问题相关的故事板部分的图像:
以下是代码的流程:
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不是问题,并且它与我设置它时有关。 可能是约束被重置或搞砸了?
答案 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
}