【问题标题】:Swift: adding SwiftUI element to UIKit project: unable to apply constraints correctlySwift:将 SwiftUI 元素添加到 UIKit 项目:无法正确应用约束
【发布时间】: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)。但无论我尝试限制什么元素,我都会收到此错误。

【问题讨论】:

    标签: swift swiftui autolayout constraints dropdown


    【解决方案1】:

    您从未将 UIHostingController 添加到父 ViewController

    通常你会这样做:

    addChild(controller)
    view.addSubview(controller.view)
    controller.didMove(toParent: self)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-10-31
      • 1970-01-01
      • 2015-10-20
      • 1970-01-01
      • 2020-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多