为什么我的UI元素在动画/缩小屏幕后没有正确重置?
因此,我会尽可能多地提供有关此项目的信息,因为我可以提前做好准备。这里是故事板的部分的图像是相关的问题:为什么我的UI元素在动画/缩小屏幕后没有正确重置?
这里是代码的流程:
1)用户玩游戏。这会加剧所显示的表情符号,并最终隐藏右侧的所有表情符号。
2)当有人赢得比赛,它调用
performSegue(withIdentifier: "ShowWinScreenSegue", sender: self)
将执行红色箭头指向的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。所以我把resetGameToMatchState
的全身放在DispatchQueue.main.async
的电话里。这没有做任何事情。
然后,我认为它之前工作,因为当WinScreenSegue之前被解雇(当它是一个“秀”赛格),它被称为GameController
的ViewDidAppear
。我尝试在解雇回调中手动调用这个函数,但那也不起作用,而且感觉真的很黑。
现在我卡住了:(任何帮助,将完全理解即使它只是一点点信息,可以清理UI系统是如何工作
这里是我的resetGameToMatchState():
//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()
}
}
UPDATE
所以,我只是发现了这一点。当我尝试重置UI正在重置右侧的表情符号到原来的位置不工作的唯一的事情。我要做的就是在开始该应用程序(在viewDidLoad)我运行这个:
for emoji in currentEmojiLabels! {
currentEmojiLabelInitFrames.append(emoji.frame)
}
这节省了它们原来的位置以备后用。我这样做是因为我在隐藏它们之前将它们设置为屏幕的一侧。
现在,当我想重置自己的立场,我这样做:
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
}
这应该他们都设置为原来的框架和规模,但它并没有正确设置的位置。它虽然重设规模。奇怪的是,我可以在屏幕左侧看到一小部分表情符号,当它们动画时,它们从左边的很远处开始动画。我试图想为什么帧等客...
更新2
所以我试图改变帧复位代码如下:
emoji.frame = CGRect(x: 25, y: 25, width: 25, height: 25)
而且我认为他应该重新设置正确地放在左上角,但它仍然推向左边。这应该证明当前的EmojiLabelInitFrames不是问题,并且在设置它们时与它有关。 也许约束正在重置或混乱?
当模型WinScreenController
被解雇时,您的第一个屏幕GameController
应该从UIKit收到viewWillAppear
回调。
所以其resetGameToMatchState
功能,可以简单地将属性设置为true
,那么你的现有resetGameToMatchState
可以移动到viewWillAppear
,首先检查是否属性被设置。
var resetNeeded: Bool = false
func resetGameToMatchState() {
resetNeeded = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// reset code here
}
这就是我的想法,但当segue被解雇时,viewWillAppear不会被调用。我认为这是因为它是一个叠加层,所以在技术上它的整个时间都是可见的。 – Diericx
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
}
'self.delegate?'必须在vc解散后为零。 – Ryan
为什么每次都分配一个'GameState'的新实例?委托方法有什么作用? “viewWill/DidAppear”在第一个VC中会做什么? – Paulw11
@Ryan你是什么意思?我应该把它设置为零? – Diericx