Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
92 views
in Technique[技术] by (71.8m points)

ios - Programmatically assigning class to a UIView created in Storyboard (Swift)

Question: How do I programmatically assign a class to a UIView created in Storyboard?

I have a UIView created in IB (graphView) in which I would like to display one of several graphs, their definitions created in their respective classes.

To do this, I created another view programmatically then assigned the class of the selected graph to that view, then added it to the original view:

@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)
}

Things seem to work, but do I really need that second UIView (selectedGraphView)?

I tried changing it to:

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

but I don't know how to get the contents of the class to run.

Can I do it this way? If so, what is missing?

EDIT: Actually, there are 3 UIViews: the one in IB, the one to hold the graph, and the class itself creates one.

If, say class1 has nothing but print("entered class1"), in the first case (displayGraph), I see "entered class1" printed. In the second (displayGraph2), I get nothing.

EDIT2: I can assign any of the classes to graphView in IB and get the print message from the class. How do I assign a class to graphView programmatically (since what I attempted in displayGraph2 doesn't work)?

question from:https://stackoverflow.com/questions/65623672/programmatically-assigning-class-to-a-uiview-created-in-storyboard-swift

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

When you add a UIView in Storyboard, you can assign its Custom Class. However, at run-time, you cannot change its class this way:

@IBOutlet var graphViewHolder: UIView!

override func viewDidLoad() {
    super.viewDidLoad()

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

}

One common approach, as you've done, is to add a UIView in your Storyboard as a "holder" (or "container") view. Then, in code, instantiate an instance of your desired Custom Class and add it as a subview to the "holder" view.

However, if you do this:

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

The newly added subview will have the size of the "holder" view, and you'll run into layout issues if / when the holder view changes size (such as on device rotation).

So, you can do it like this:

// 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),
    ])
}

Now the subview will follow the "holder" view's constraints.

Note that if you want to do something to the loaded view, you'll have to make sure it's the right class.

So, for example, if we want to call a custom func in 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()

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...