Swift:将 SwiftUI 元素添加到 UIKit 项目:无法正确应用约束
Posted
技术标签:
【中文标题】Swift:将 SwiftUI 元素添加到 UIKit 项目:无法正确应用约束【英文标题】:Swift: adding SwiftUI element to UIKit project: unable to apply constraints correctly 【发布时间】:2020-12-07 16:00:37 【问题描述】:我正在尝试将使用 SwiftUI 构建的下拉元素添加到我的 UIKit 项目中。
我有一个自定义 UIView,其中包含多个堆栈视图,包括这个:
internal lazy var valueWithDataUnitStack: UIStackView =
var stackSubviews = [inputField, dataUnitLabel]
let stack = UIStackView(arrangedSubviews: stackSubviews)
stack.axis = .horizontal
stack.spacing = Constants.FontAttributes.valueUnitStackSpacing
return stack
()
我已经使用 SwiftUI 构建了以下下拉列表:
import SwiftUI
@available(ios 14.0.0, *)
struct DataUnitDropDown: View
var units = ["ltr", "usg", "impg"]
@State private var selectedDataUnit = 0
@State private var isExpanded = false
var body: some View
VStack(alignment: .leading, spacing: 15)
DisclosureGroup(units[selectedDataUnit], isExpanded: $isExpanded)
VStack
ForEach(0 ..< units.count, id: \.self) index in
Text("\(units[index])")
.font(.system(size: 14))
.padding(.all)
.onTapGesture
self.selectedDataUnit = index
self.isExpanded.toggle()
我还有一个名为“isDynamic”的变量。当它在 init 中设置为 'true' 时,而不是有
[inputField, dataUnitLable]
我想要的是:
[inputField, controller.view]
(其中控制器是注入此 SwiftUI 元素所需的 UIHostingController。所以我尝试了以下方法:
internal lazy var valueWithDataUnitStack: UIStackView =
var stackSubviews = [UIView]()
if let isDynamic = isDynamicField, isDynamic
stackSubviews = [inputField]
if #available(iOS 14.0.0, *)
let controller = UIHostingController(rootView: DataUnitDropDown())
controller.view.translatesAutoresizingMaskIntoConstraints = false
controller.view.clipsToBounds = false
addSubview(controller.view)
controller.view.heightAnchor.constraint(equalToConstant: titleLabel.heightAnchor).isActive = true
controller.view.topAnchor.constraint(equalTo: titleLabel.topAnchor).isActive = true
stackSubviews = [inputField, controller.view]
else
stackSubviews = [inputField, dataUnitLabel]
let stack = UIStackView(arrangedSubviews: stackSubviews)
stack.axis = .horizontal
stack.spacing = Constants.FontAttributes.valueUnitStackSpacing
return stack
()
所以上面的想法是我需要强制下拉保持与顶部的其他元素对齐。我还需要允许下拉菜单展开而不影响它所在的堆栈的高度,因此我将 clipToBounds 设置为 false。
但是,每当我尝试访问这些约束中的任何一个时,我都会崩溃:
Thread 1: "Unable to activate constraint with anchors <NSLayoutDimension:0x60000352f880 \"_TtGC7SwiftUI14_UIHostingViewV10eHandshake16DataUnitDropDown_:0x7fbbdd381960.height\"> and <NSLayoutDimension:0x60000352f8c0 \"UITextField:0x7fbbdb4c33d0.height\"> because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal."
如何将此元素注入堆栈并利用自定义 UIView 类中的现有约束。
注意:我可以尝试将其他 UI 元素用作锚点(例如,titleLabel 是此自定义类中的另一个 UILabel)。但无论我尝试限制什么元素,我都会收到此错误。
【问题讨论】:
【参考方案1】:您从未将 UIHostingController 添加到父 ViewController
通常你会这样做:
addChild(controller)
view.addSubview(controller.view)
controller.didMove(toParent: self)
【讨论】:
以上是关于Swift:将 SwiftUI 元素添加到 UIKit 项目:无法正确应用约束的主要内容,如果未能解决你的问题,请参考以下文章
在 SwiftUI 中的 forEach 期间将文本字段输入添加到数组
如何在swift ui中使用autoid将带有字段的新文档添加到firebase集合