简体   繁体   中英

How to connect a swiftUI button to an NSView action?

I have a small start on a SwiftUI app. I'm trying to connect a button to an action in an NSView that I've added to the body of the SwiftUI.

I can't figure out how to reference the DrawingView inside the action of the button so that I can call the toggleDrawingType action. I've found no developer documentation that gives any hints as to how to go about this.

------- ContentView.swift -------
import SwiftUI

struct ContentView : View {
    var body: some View {
        VStack {
            HStack {
                Text("Hello")
                Image("LineTool")
                Button(action: {}) {
                    Image("CenterCircleTool")
                }
            }
            DrawingView()
        }
    }
}

-------- DrawingView.swift --------

import SwiftUI

public struct DrawingView: NSViewRepresentable {
    public typealias NSViewType = DrawingViewImplementation

    public func makeNSView(context: NSViewRepresentableContext<DrawingView>) -> DrawingViewImplementation {
        return DrawingViewImplementation()
    }

    public func updateNSView(_ nsView: DrawingViewImplementation, context: NSViewRepresentableContext<DrawingView>) {
        nsView.setNeedsDisplay(nsView.bounds)
    }
}

enum DrawingType {
    case Rect
    case Circle
}

public class DrawingViewImplementation: NSView {

    var currentType = DrawingType.Rect

    override public func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)

        NSColor.blue.set()
        switch currentType {
        case .Rect:
            NSRect(x: 100, y: 100, width: 100, height: 100).frame()
        case .Circle:
            NSBezierPath(ovalIn: NSRect(x: 100, y: 100, width: 100, height: 100)).stroke()
        }
    }

    @IBAction func toggleDrawingType(sender: Any) {
        switch currentType {
        case .Rect:
            currentType = .Circle
        case .Circle:
            currentType = .Rect
        }
        setNeedsDisplay(bounds)
   }

    public override func mouseDown(with event: NSEvent) {
        toggleDrawingType(sender: self)
    }
}

I had the same problem and found a solution in the organisation of the code.

The basic problem is that a structure following the NSViewRepresentable protocol does by itself not hand out a reference to its underlying NSView.

The solution is to introduce an object which is available at the time of creation of the ViewRepresentable structure. Its reference to the view is set at the time of creation of the view.

I my eyes this is part of the bigger picture that with SwiftUI views view controllers are not any longer present. SwiftUI views depend directly on the model objects (via the @ObservableObject or @EnvironmentObject variable). Hence the model object tends to cary the functionality which before the view controller carried (or the View structure carries this functionality directly).

I hand in the model object into the initialiser of the ViewRepresentable and set a weak reference within the model object to the view created. Like this the content object is the omnipresent entity - within the ViewRepresentable and within the SwiftUI View structure.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM