首页 > 解决方案 > 以编程方式将类分配给在 Storyboard (Swift) 中创建的 UIView

问题描述

问题:如何以编程方式将类分配给在 Storyboard 中创建的 UIView?

我在 IB ( graphView) 中创建了一个 UIView,我想在其中显示几个图形之一,它们的定义在各自的类中创建。

为此,我以编程方式创建了另一个视图,然后将所选图形的类分配给该视图,然后将其添加到原始视图中:

@IBOutlet weak var graphView: UIView!

func displayGraph(choice: Int) {
    var selectedGraphView = UIView()        
    switch choice {
        case 1: selectedGraphView = class1()
        case 2: selectedGraphView = class2()
        case 3: selectedGraphView = class3()
        default: selectedGraphView = class1()
    }
    selectedGraphView.frame = CGRect(x: 0, y: 0, width: graphView, height: graphView)
    graphView.addSubview(selectedGraphView)
}

事情似乎奏效了,但我真的需要第二个 UIView ( selectedGraphView) 吗?

我尝试将其更改为:

func displayGraph2(choice: Int) {
    switch choice {
        case 1: graphView = class1()
        case 2: graphView = class2()
        case 3: graphView = class3()
        default: graphView = class1()
    }
}

但我不知道如何让类的内容运行。

我可以这样做吗?如果是这样,缺少什么?

编辑:实际上,有 3 个 UIView:IB 中的一个,保存图形的一个,类本身创建一个。

如果 sayclass1只有print("entered class1"),在第一种情况下 ( displayGraph),我看到打印了“进入的 class1”。在第二个(displayGraph2)中,我什么也没得到。

EDIT2:我可以将任何课程分配给graphViewIB 并从课程中获取打印消息。如何以graphView编程方式分配一个类(因为我尝试的方法displayGraph2不起作用)?

标签: iosswift

解决方案


当您UIView在 Storyboard 中添加一个时,您可以分配它的自定义类。但是,在运行时,您不能以这种方式更改其类:

@IBOutlet var graphViewHolder: UIView!

override func viewDidLoad() {
    super.viewDidLoad()

    // cannot do this
    let v = View2Class()
    graphViewHolder = v

}

正如您所做的那样,一种常见的方法是UIView在您的故事板中添加一个作为“持有者”(或“容器”)视图。然后,在代码中,实例化所需自定义类的实例并将其作为子视图添加到“持有人”视图。

但是,如果您这样做:

selectedGraphView.frame = CGRect(x: 0, y: 0, width: graphView, height: graphView)
graphView.addSubview(selectedGraphView)

新添加的子视图将具有“持有人”视图的大小,如果/当持有人视图改变大小时(例如设备旋转),您将遇到布局问题。

所以,你可以这样做:

// let's name it "graphViewHolder" so we know we're using it as a "holder" view
@IBOutlet var graphViewHolder: UIView!

var currentChoice: Int = 1

override func viewDidLoad() {
    super.viewDidLoad()

    displayGraph(choice: 1)
}

func displayGraph(choice: Int) {
    var selectedGraphView: UIView?
    switch choice {
    case 1: selectedGraphView = View1Class()
    case 2: selectedGraphView = View2Class()
    case 3: selectedGraphView = View3Class()
    default: selectedGraphView = View1Class()
    }
    // unwrap optional
    guard let sgv = selectedGraphView else { return }
    // does the "holder" view already have any subviews?
    //  if so, remove them
    graphViewHolder.subviews.forEach { v in
        v.removeFromSuperview()
    }
    // add the new view as a subview of the "holder" view
    graphViewHolder.addSubview(sgv)
    // we need to give the new view auto-layout properties
    sgv.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
        // constrain it to all 4 sides of the "holder" view
        sgv.topAnchor.constraint(equalTo: graphViewHolder.topAnchor),
        sgv.leadingAnchor.constraint(equalTo: graphViewHolder.leadingAnchor),
        sgv.trailingAnchor.constraint(equalTo: graphViewHolder.trailingAnchor),
        sgv.bottomAnchor.constraint(equalTo: graphViewHolder.bottomAnchor),
    ])
}

现在子视图将遵循“持有人”视图的约束。

请注意,如果您想对加载的视图执行某些操作,则必须确保它是正确的类。

因此,例如,如果我们想在 中调用自定义函数View2Class

    // make sure the "holder" view has a subview
    guard let v = graphViewHolder.subviews.first else {
        print("Graph View Holder has no subviews!")
        return
    }
    // make sure the subview is a View2Class instance
    guard let v2 = v as? View2Class else {
        print("The Holder subview is not View2Class!")
        return
    }
    // call a func in View2Class
    v2.myFunc()

推荐阅读