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

问题描述:

因此,我会尽可能多地提供有关此项目的信息,因为我可以提前做好准备。这里是故事板的部分的图像是相关的问题:为什么我的UI元素在动画/缩小屏幕后没有正确重置?

enter image description here

这里是代码的流程:

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之前被解雇(当它是一个“秀”赛格),它被称为GameControllerViewDidAppear。我尝试在解雇回调中手动调用这个函数,但那也不起作用,而且感觉真的很黑。

现在我卡住了:(任何帮助,将完全理解即使它只是一点点信息,可以清理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不是问题,并且在设置它们时与它有关。 也许约束正在重置或混乱?

+0

'self.delegate?'必须在vc解散后为零。 – Ryan

+0

为什么每次都分配一个'GameState'的新实例?委托方法有什么作用? “viewWill/DidAppear”在第一个VC中会做什么? – Paulw11

+0

@Ryan你是什么意思?我应该把它设置为零? – Diericx

当模型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 
} 
+0

这就是我的想法,但当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 
}