Xcode:AutoLayout/Storyboard 与 UICollectionView 问题
Xcode: AutoLayout/Storyboard with UICollectionView Issue
简短问题:Xcode 中 Storyboard 上的 "View As" 功能与您的 App 在模拟器中的视觉显示方式之间是否存在相关性?
长问题:
我正在开发一个 Schedule 应用程序,在该应用程序中 ViewController 顶部有一个 CollectionView,它允许您 select 一个日期来加载一个时间表,即您可以 select 明天要计划你的日程,你可以select今天、昨天或更远的过去或未来。
在我的项目中,我有这段代码,到 select 当前日期。
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
dateCollectionView.selectItem(at: IndexPath.init(item: CalendarModel.CURRENT_DAY, section: 0), animated: true, scrollPosition: .centeredHorizontally)
}
现在,当我 运行 项目时,奇怪的事情发生了。如果我 select iPhone 11 作为 Storyboard 中的 "View as" 是这样的:
然后 运行 iPhone 11 模拟器,我的应用程序运行正常,看起来像这样:
现在,如果我 select Storyboard 中的 iPhone SE:
然后 运行 iPhone 11 上的应用程序,它看起来像这样(不工作,不显示 "Today"):
现在奇怪的事情发生了,如果我现在 select iPhone 8,它与 iPhone SE 大小相同,同时仍然有 iPhone SE select编入故事板。它现在可以工作了,如您所见:
如果我在 "View As" 部分也有 iPhone SE selected 并尝试 运行 它在我的物理 iPhone XS 上,我得到同样的问题。
所以我的问题是,这是一个 Xcode 错误吗?假设我在 Appstore 上发布了这个应用程序,它是否只能在某些设备上运行?有没有办法防止这种情况?
我在 GitHub 上发布了一个最小可重现示例:
github.com/julianboyko/Power-Planner-MRE
我几乎可以肯定这是 Storyboard 问题,这与我必须使用的 StackView 以及使用的约束有关。
谢谢。
您是否尝试过使用 cmd+shift+k 清理您的构建?它可能不会做任何事情,但不会伤害尝试。同样在第二个屏幕截图上,它的位置不相等,但以编程方式将其设置为居中,您是否检查了所有约束(再次不知道为什么这会改变显示的样式但值得一试)。
模拟器中的各种设备都有自己的状态。您的应用程序可能安装在其中一些设备上而不是其他设备上,并且该应用程序在安装它的每台设备上的状态都是特定于该设备的。
您的应用似乎默认显示当前日期,但它还会保存所选日期并在下次运行时使用该日期。无论如何,这是非常合理的行为,所以为了争论起见,我们假设它就是这样做的。如果您上周在 iPhone 11 模拟器上 运行 您的应用程序,那么您的应用程序可能会将该日期保存为所选日期。当您最近在其他未安装它的设备上再次 运行 它时,该应用程序会“重新启动”并选择当前日期。但是当你 运行 它在 iPhone 11 时,应用程序已经有一些保存的数据,所以它使用它而不是回退到默认行为。
请注意,即使您重建应用程序并在 iPhone 11 模拟器上再次安装,也会出现这种情况。当您重建应用程序时,Xcode 安装新应用程序但保留应用程序的现有数据,就像您从 App Store 更新应用程序一样。如果您希望应用程序像新安装的一样启动,只需在构建之前从模拟器中删除它。
问题是您正在调用:
dateCollectionView.selectItem(at: IndexPath.init(item: CalendarModel.CURRENT_DAY, section: 0), animated: true, scrollPosition: .centeredHorizontally)
在 viewWillAppear()
内,此时自动布局尚未确定框架。
相反,您需要在所有视图都布置好后调用它。注释掉你的整个 viewWillAppear()
func,然后这样试试:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
dateCollectionView.selectItem(at: IndexPath.init(item: CalendarModel.CURRENT_DAY, section: 0), animated: false, scrollPosition: .centeredHorizontally)
}
简短问题:Xcode 中 Storyboard 上的 "View As" 功能与您的 App 在模拟器中的视觉显示方式之间是否存在相关性?
长问题: 我正在开发一个 Schedule 应用程序,在该应用程序中 ViewController 顶部有一个 CollectionView,它允许您 select 一个日期来加载一个时间表,即您可以 select 明天要计划你的日程,你可以select今天、昨天或更远的过去或未来。
在我的项目中,我有这段代码,到 select 当前日期。
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
dateCollectionView.selectItem(at: IndexPath.init(item: CalendarModel.CURRENT_DAY, section: 0), animated: true, scrollPosition: .centeredHorizontally)
}
现在,当我 运行 项目时,奇怪的事情发生了。如果我 select iPhone 11 作为 Storyboard 中的 "View as" 是这样的:
然后 运行 iPhone 11 模拟器,我的应用程序运行正常,看起来像这样:
现在,如果我 select Storyboard 中的 iPhone SE:
然后 运行 iPhone 11 上的应用程序,它看起来像这样(不工作,不显示 "Today"):
现在奇怪的事情发生了,如果我现在 select iPhone 8,它与 iPhone SE 大小相同,同时仍然有 iPhone SE select编入故事板。它现在可以工作了,如您所见:
如果我在 "View As" 部分也有 iPhone SE selected 并尝试 运行 它在我的物理 iPhone XS 上,我得到同样的问题。
所以我的问题是,这是一个 Xcode 错误吗?假设我在 Appstore 上发布了这个应用程序,它是否只能在某些设备上运行?有没有办法防止这种情况?
我在 GitHub 上发布了一个最小可重现示例:
github.com/julianboyko/Power-Planner-MRE
我几乎可以肯定这是 Storyboard 问题,这与我必须使用的 StackView 以及使用的约束有关。
谢谢。
您是否尝试过使用 cmd+shift+k 清理您的构建?它可能不会做任何事情,但不会伤害尝试。同样在第二个屏幕截图上,它的位置不相等,但以编程方式将其设置为居中,您是否检查了所有约束(再次不知道为什么这会改变显示的样式但值得一试)。
模拟器中的各种设备都有自己的状态。您的应用程序可能安装在其中一些设备上而不是其他设备上,并且该应用程序在安装它的每台设备上的状态都是特定于该设备的。
您的应用似乎默认显示当前日期,但它还会保存所选日期并在下次运行时使用该日期。无论如何,这是非常合理的行为,所以为了争论起见,我们假设它就是这样做的。如果您上周在 iPhone 11 模拟器上 运行 您的应用程序,那么您的应用程序可能会将该日期保存为所选日期。当您最近在其他未安装它的设备上再次 运行 它时,该应用程序会“重新启动”并选择当前日期。但是当你 运行 它在 iPhone 11 时,应用程序已经有一些保存的数据,所以它使用它而不是回退到默认行为。
请注意,即使您重建应用程序并在 iPhone 11 模拟器上再次安装,也会出现这种情况。当您重建应用程序时,Xcode 安装新应用程序但保留应用程序的现有数据,就像您从 App Store 更新应用程序一样。如果您希望应用程序像新安装的一样启动,只需在构建之前从模拟器中删除它。
问题是您正在调用:
dateCollectionView.selectItem(at: IndexPath.init(item: CalendarModel.CURRENT_DAY, section: 0), animated: true, scrollPosition: .centeredHorizontally)
在 viewWillAppear()
内,此时自动布局尚未确定框架。
相反,您需要在所有视图都布置好后调用它。注释掉你的整个 viewWillAppear()
func,然后这样试试:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
dateCollectionView.selectItem(at: IndexPath.init(item: CalendarModel.CURRENT_DAY, section: 0), animated: false, scrollPosition: .centeredHorizontally)
}