iOS 16.0下图形样式DatePicker触发布局约束冲突问题
在Xcode-14.0.0-Beta 5、iOS 16.0环境下运行以下代码时,会触发布局约束冲突:
struct ContentView: View { @State var date = Date() var body: some View { DatePicker(selection: $date, displayedComponents: .date, label: { EmptyView() }) .datePickerStyle(.graphical) } }
控制台警告信息
2022-08-24 17:16:40.471325+0300 DatePickerProblem[77364:483284] [布局约束] 无法同时满足多个约束条件。
以下列表中至少有一个约束是你不需要的。
请尝试:
(1) 检查每个约束,找出不符合预期的约束;
(2) 找到添加该约束的代码并修复。
(注意:如果遇到无法理解的NSAutoresizingMaskLayoutConstraints,请参考UIView属性translatesAutoresizingMaskIntoConstraints的文档)
(
"<NSAutoresizingMaskLayoutConstraint:0x600003559180 h=--& v=--& _UIDatePickerCalendarTimeView:0x7fe15c322520.height == 0 (active)>",
"<NSLayoutConstraint:0x60000352bca0 _UIDatePickerCompactTimeLabel:0x7fe15c322bc0.centerY == _UIDatePickerCalendarTimeView:0x7fe15c322520.centerY - 1 (active)>",
"<NSLayoutConstraint:0x60000352bcf0 V:|-(>=0)-[_UIDatePickerCompactTimeLabel:0x7fe15c322bc0] (active, names: '|':_UIDatePickerCalendarTimeView:0x7fe15c322520 )>"
)
将尝试通过打破以下约束恢复:
<NSLayoutConstraint:0x60000352bca0 _UIDatePickerCompactTimeLabel:0x7fe15c322bc0.centerY == _UIDatePickerCalendarTimeView:0x7fe15c322520.centerY - 1 (active)>
在UIViewAlertForUnsatisfiableConstraints处设置符号断点,可在调试器中捕获该问题。
<UIKitCore/UIView.h>中列出的UIView的UIConstraintBasedLayoutDebugging分类中的方法也会有所帮助。2022-08-24 17:16:40.471971+0300 DatePickerProblem[77364:483284] [布局约束] 无法同时满足多个约束条件。
以下列表中至少有一个约束是你不需要的。
请尝试:
(1) 检查每个约束,找出不符合预期的约束;
(2) 找到添加该约束的代码并修复。
(注意:如果遇到无法理解的NSAutoresizingMaskLayoutConstraints,请参考UIView属性translatesAutoresizingMaskIntoConstraints的文档)
(
"<NSAutoresizingMaskLayoutConstraint:0x600003559180 h=--& v=--& _UIDatePickerCalendarTimeView:0x7fe15c322520.height == 0 (active)>",
"<NSLayoutConstraint:0x60000352bd40 UILabel:0x7fe15c324d00.centerY == _UIDatePickerCalendarTimeView:0x7fe15c322520.centerY - 1 (active)>",
"<NSLayoutConstraint:0x60000352bd90 V:|-(>=0)-[UILabel:0x7fe15c324d00] (active, names: '|':_UIDatePickerCalendarTimeView:0x7fe15c322520 )>"
)
将尝试通过打破以下约束恢复:
<NSLayoutConstraint:0x60000352bd40 UILabel:0x7fe15c324d00.centerY == _UIDatePickerCalendarTimeView:0x7fe15c322520.centerY - 1 (active)>
在UIViewAlertForUnsatisfiableConstraints处设置符号断点,可在调试器中捕获该问题。
<UIKitCore/UIView.h>中列出的UIView的UIConstraintBasedLayoutDebugging分类中的方法也会有所帮助。2022-08-24 17:16:40.478778+0300 DatePickerProblem[77364:483284] [布局约束] 无法同时满足多个约束条件。
以下列表中至少有一个约束是你不需要的。
请尝试:
(1) 检查每个约束,找出不符合预期的约束;
(2) 找到添加该约束的代码并修复。
(注意:如果遇到无法理解的NSAutoresizingMaskLayoutConstraints,请参考UIView属性translatesAutoresizingMaskIntoConstraints的文档)
(
"<_UISystemBaselineConstraint:0x60000355c190 H:[UILabel:0x7fe15c324d00]-(>=NSLayoutAnchorConstraintSpace(8))-[_UIDatePickerCompactTimeLabel:0x7fe15c322bc0] (active)>",
"<NSAutoresizingMaskLayoutConstraint:0x6000035590e0 h=--& v=--& _UIDatePickerCalendarTimeView:0x7fe15c322520.width == 0 (active)>",
"<NSLayoutConstraint:0x60000352bf20 UILabel:0x7fe15c324d00.leading == UILayoutGuide:0x600002f06760'UIViewLayoutMarginsGuide'.leading (active)>",
"<NSLayoutConstraint:0x60000355c230 _UIDatePickerCompactTimeLabel:0x7fe15c322bc0.trailing == UILayoutGuide:0x600002f06760'UIViewLayoutMarginsGuide'.trailing (active)>",
"<NSLayoutConstraint:0x60000352be30 'UIView-leftMargin-guide-constraint' H:|-(8)-UILayoutGuide:0x600002f06760'UIViewLayoutMarginsGuide' (active, names: '|':_UIDatePickerCalendarTimeView:0x7fe15c322520 )>",
"<NSLayoutConstraint:0x60000352bed0 'UIView-rightMargin-guide-constraint' H:[UILayoutGuide:0x600002f06760'UIViewLayoutMarginsGuide']-(8)-|(LTR) (active, names: '|':_UIDatePickerCalendarTimeView:0x7fe15c322520 )>"
)
将尝试通过打破以下约束恢复:
<_UISystemBaselineConstraint:0x60000355c190 H:[UILabel:0x7fe15c324d00]-(>=NSLayoutAnchorConstraintSpace(8))-[_UIDatePickerCompactTimeLabel:0x7fe15c322bc0] (active)>
在UIViewAlertForUnsatisfiableConstraints处设置符号断点,可在调试器中捕获该问题。
<UIKitCore/UIView.h>中列出的UIView的UIConstraintBasedLayoutDebugging分类中的方法也会有所帮助。2022-08-24 17:16:40.512015+0300 DatePickerProblem[77364:483284] [UICalendarView] UICalendarView的高度小于其内容所需的最小高度,将默认使用最小高度。
2022-08-24 17:16:40.548888+0300 DatePickerProblem[77364:483284] [UICalendarView] UICalendarView的高度小于其内容所需的最小高度,将默认使用最小高度。
修复方案
方案1:给DatePicker指定明确的尺寸约束
从警告可以看出,_UIDatePickerCalendarTimeView被强制设置为宽高0,但内部标签仍有布局约束,导致冲突。给DatePicker添加最小高度约束,能避免系统生成无效的尺寸约束:
struct ContentView: View { @State var date = Date() var body: some View { DatePicker(selection: $date, displayedComponents: .date, label: { EmptyView() }) .datePickerStyle(.graphical) .frame(minHeight: 300) // 适配日历内容的最小高度 } }
方案2:替换EmptyView为透明占位文本
直接使用EmptyView()可能导致系统内部布局逻辑异常。用透明文本替代,既隐藏视觉效果,又能维持布局结构的完整性:
struct ContentView: View { @State var date = Date() var body: some View { DatePicker(selection: $date, displayedComponents: .date, label: { Text(" ").opacity(0) }) .datePickerStyle(.graphical) } }
方案3:升级Xcode版本
这是iOS 16 Beta版本的系统bug,后续Xcode 14正式版及更新版本已修复该问题。升级到正式版即可彻底解决约束冲突。
方案4:临时隐藏警告(不推荐)
如果暂时无法升级或修改代码,可通过以下方式临时隐藏警告,但会影响调试便利性:
- 在Xcode的
Edit Scheme->Run->Arguments->Environment Variables中添加OS_ACTIVITY_MODE,值设为disable(会隐藏所有控制台日志)。 - 用
UIViewRepresentable包装DatePicker,禁用子视图的约束警告:
extension UIView { func disableConstraintWarnings() { self.translatesAutoresizingMaskIntoConstraints = false subviews.forEach { $0.disableConstraintWarnings() } } } struct FixedDatePicker: UIViewRepresentable { @Binding var date: Date func makeUIView(context: Context) -> UIDatePicker { let picker = UIDatePicker() picker.datePickerMode = .date picker.preferredDatePickerStyle = .inline picker.addTarget(context.coordinator, action: #selector(Coordinator.updateDate), for: .valueChanged) picker.disableConstraintWarnings() return picker } func updateUIView(_ uiView: UIDatePicker, context: Context) { uiView.date = date } func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject { var parent: FixedDatePicker init(_ parent: FixedDatePicker) { self.parent = parent } @objc func updateDate(_ picker: UIDatePicker) { parent.date = picker.date } } } // 使用方式 struct ContentView: View { @State var date = Date() var body: some View { FixedDatePicker(date: $date) } }
内容的提问来源于stack exchange,提问作者Claudiu

