我有两个班级:
class Glyph: ObservableObject {
...
@Published var manager: CoordinatesManager {
didSet {
print ("MANAGER DID SET IN GLYPH, \(manager.currentCoordinates)")
}
}
@Published var elements: [ MultidimensionalPoints ]
var path: Path {
var resultPath = Path()
if self.elements.count > 1 {
//count path, path elements depends on manager.currentCoordinates
}
}
return resultPath
}
}
class CoordinatesManager {
...
@Published var currentCoordinates: [ Coordinate ]
...
}
现在我尝试构建SwiftUI视图层次结构。在一个视图中,我需要显示Glyph
对象,在另一个视图中,需要显示一些滑块以更改manager.currentCoordinates
。当然,每个更改都应在第一视图中反映出来,因为它更改了glyph.manager.currentCoordinates
。
public struct ContentView: View
{
@EnvironmentObject var glyph: Glyph
var body: some View {
NavigationView {
GlyphView()
VStack {
CoordinatesView(coordinates: $glyph.manager.currentCoordinates)
Text ("updated manager coordinates\(glyph.manager.currentCoordinates.description)").controlSize(.mini)
}
}
}
}
CoordinatesView没什么特别的:只是滑动条就可以了。 glyph.manager
didSet
打印更改的值。
MANAGER DID SET IN GLYPH, ["width" <min>, "weight" <min>, "contrast" <min>]
MANAGER DID SET IN GLYPH, ["width" 1.72, "weight" <min>, "contrast" <min>]
MANAGER DID SET IN GLYPH, ["width" 3.45, "weight" <min>, "contrast" <min>]
....
GlyphView:
public struct GlyphView: View
{
@EnvironmentObject var glyph: Glyph
public var body: some View {
ZStack {
// This is called only when i change View size
// GlyphShape generates some Shape based on Glyph.currentState
GlyphShape(glyph: glyph).stroke()
Text("Overlay for test")
}
}
}
此视图应该对glyph.manager.currentCoordinates
中的更改做出反应,但是没有,我也不知道该怎么做。 仅当我更改视图大小时发生反应(通过鼠标)
struct GlyphShape: Shape
{
@ObservedObject var glyph: Glyph
func path(in rect: CGRect) -> Path {
let glyphPath = glyph.path
... // transform
print ("MAKING SHAPE @\(glyph.manager.currentCoordinates) \(resultPath)")
return resultPath
}
}
每次我在GlyphShape的导航器视图func path(in: rect)
上方滚动(而不是移动)光标时,都会触发并在终端中打印实际的manager.currentCoordinates
和新路径。
MAKING SHAPE @["width" <min>, "weight" <min>, "contrast" 29.94] TransformedShape<Path>(shape: 50 70 m 158.264 295.569 l 150 100 l 650 410 l, transform: __C.CGAffineTransform(a: 1.0433333333333332, b: 0.0, c: 0.0, d: 1.0433333333333332, tx: 0.0, ty: 0.0)) CCC
MAKING SHAPE @["width" <min>, "weight" <min>, "contrast" 29.94] TransformedShape<Path>(shape: 50 70 m 158.264 295.569 l 150 100 l 650 410 l, transform: __C.CGAffineTransform(a: 1.0433333333333332, b: 0.0, c: 0.0, d: 1.0433333333333332, tx: 0.0, ty: 0.0)) CCC
路径已重新定义,但视图未刷新。
我应该如何告诉Glyph manager.coordinates已更改并将其反映在GlyphView中?
这是一个简化的Playground文件。
import AppKit
import PlaygroundSupport
import SwiftUI
let nibFile = NSNib.Name("MyView")
var topLevelObjects : NSArray?
Bundle.main.loadNibNamed(nibFile, owner:nil, topLevelObjects: &topLevelObjects)
let views = (topLevelObjects as! Array<Any>).filter { $0 is NSView }
// Present the view in Playground
PlaygroundPage.current.liveView = views[0] as! NSView
protocol AxisProtocol {
var name: String {get}
var bounds: ClosedRange<Double> {get}
}
struct Axis: AxisProtocol {
var name: String
var bounds: ClosedRange<Double>
}
struct Coordinate<Axis:AxisProtocol> {
var axis: Axis
var at: Double
}
class CoordinatesManager {
@Published var currentCoordinates: [ Coordinate<Axis> ]
init (at: [Coordinate<Axis>]) {
self.currentCoordinates = at
}
}
class ItsCompliacated {
func getSomeValue(at: [Coordinate<Axis>]) -> NSPoint {
//Counting this value is rather comlicated thing...
return NSPoint(x: Double.random(in: 0...500), y: Double.random(in: 0...500))
}
}
class Glyph: ObservableObject {
@Published var manager: CoordinatesManager {
didSet {
print (manager)
}
}
var elements: [ ItsCompliacated ] = []
var path: Path {
var result = Path()
if elements.count > 1 {
result.addLines(elements.map({$0.getSomeValue(at: manager.currentCoordinates)}))
}
return result
}
init (elements:[ItsCompliacated], manager:CoordinatesManager) {
self.manager = manager
self.elements = elements
}
}
let x = Axis(name: "x", bounds: 0...1000)
let y = Axis(name: "y", bounds: 0...1000)
let z = Axis(name: "z", bounds: 0...1000)
let cx = Coordinate(axis: x, at: 100)
let cy = Coordinate(axis: y, at: 200)
let cz = Coordinate(axis: z, at: 200)
let manager = CoordinatesManager(at: [cx, cy, cz])
let glyph = Glyph(elements: Array(repeating: ItsCompliacated(), count: 300), manager: manager)
public struct NavigatorView: View
{
@EnvironmentObject var glyph: Glyph
public var body: some View {
ZStack {
GlyphShape(glyph: glyph).stroke()
}
}
}
public struct CoordinateView : View {
@Binding var coordinate: Coordinate<Axis>
public var body : some View {
VStack (alignment: .leading, spacing: 0 ) {
HStack(alignment: .top, spacing: 0) {
Text(coordinate.axis.name).font(.system(size: 8))
Spacer(minLength: 5)
Text("\(String(format: "%.2f", coordinate.at))").font(.system(size: 8))
}
Slider(value: $coordinate.at, in: coordinate.axis.bounds)
.controlSize(.mini)
.labelsHidden()
.padding(EdgeInsets(top: -8, leading: 0, bottom: -10, trailing: 0))
}
}
}
public struct CoordinatesView : View {
@Binding var coordinates: [Coordinate<Axis>]
public var body: some View {
VStack (alignment: .leading, spacing: 0 ) {
List ((0..<coordinates.count), id:\.self) { coordinateIndex in
CoordinateView(coordinate: self.$coordinates[coordinateIndex])
}
}
}
}
struct GlyphShape: Shape {
@ObservedObject var glyph: Glyph
func path(in rect: CGRect) -> Path {
let glyphPath = glyph.path
print ("MAKING SHAPE")
return glyphPath
}
}
struct ContentView: View {
@EnvironmentObject var glyph: Glyph
var body: some View {
VStack {
NavigatorView()
.frame(width: 500, height: 500, alignment: .top)
CoordinatesView(coordinates: $glyph.manager.currentCoordinates)
.frame(minWidth: 500, idealWidth: 500, maxWidth: 500, minHeight: 300, idealHeight: .none, maxHeight: 500, alignment: .bottom)
//.frame(minWidth: .none, idealWidth: 500, maxWidth: .none, minHeight: .none, idealHeight: .none, maxHeight: .none, alignment: .bottom)
}
}
}
PlaygroundPage.current.setLiveView(ContentView().environmentObject(glyph))
答案 0 :(得分:0)
字形和CoordinatesManager应该符合ObservableObject
。
也看不到它们的初始化位置。
如果您传递manager
而不是glyph.manager
,那么显然glyph
不会收到通知。
只需使用@EnvironmentObject
,您就不必在整个地方传递Binding。
平整您的结构,例如;字形和管理器位于同一级别,而不是嵌套。可能会简化调试。
答案 1 :(得分:0)
好。错误出在GlyphShape
中。代替@BindningObject
应该是@EnvironmentObject
。
所以NavigatorView
应该打电话
GlyphShape(glyph: _glyph).stroke()
仅此而已。