核心数据不会触发 SwiftUI 的立即刷新
Core data not triggering immediate refresh with SwiftUI
我对这个问题一头雾水,过去几天我一直在解决这个问题。
我正在绘制自定义形状,用户可以通过拖动手势移动其中一个点。我希望在移动点时重新绘制形状。
这是一些使用 CGPoint 的示例代码。
import SwiftUI
struct ShapeTest: Shape {
@State var points: [CGPoint]
@State var closed: Bool = true
func path(in rect: CGRect) -> Path {
var path = Path()
if (points.count > 0) {
path.move(to: points.first!)
path.addLines(points)
if closed { path.closeSubpath() }
}
return path
}
}
struct RedrawEdgeTestCGPoint: View {
@State var points = [CGPoint]()
@State var originalPosition: CGPoint? = nil
private var movePointDragGesture: some Gesture {
DragGesture(minimumDistance: 0, coordinateSpace: .local)
.onChanged { value in
if points.isEmpty {
return
}
if originalPosition == nil {
originalPosition = CGPoint(x: points.last!.x, y: points.last!.y)
}
let lastIndex = points.count - 1
points[lastIndex].x = originalPosition!.x + value.translation.width
points[lastIndex].y = originalPosition!.y + value.translation.height
}
.onEnded { value in
originalPosition = nil
}
}
private var addNewPointGesture: some Gesture {
TapGesture(count: 2)
.onEnded {
points.append(CGPoint())
}
}
var body: some View {
GeometryReader { geometry in
Group {
ShapeTest(points: points)
.stroke()
}
.contentShape(Rectangle())
.gesture(movePointDragGesture.simultaneously(with: addNewPointGesture))
}
}
}
struct RedrawEdgeTestCGPoint_Previews: PreviewProvider {
static var previews: some View {
RedrawEdgeTestCGPoint()
}
}
现在,这是另一个代码示例。这个例子大体上是一样的,但这是使用我在 Core Data 中定义的 Point 实体而不是 CGPoint。
import SwiftUI
struct RedrawEdgeTestCoreData: View {
@Environment(\.managedObjectContext) private var viewContext
@State var points: [Point] = []
@State var originalPosition: CGPoint? = nil
private var movePointDragGesture: some Gesture {
DragGesture(minimumDistance: 0, coordinateSpace: .local)
.onChanged { value in
if points.isEmpty {
return
}
if originalPosition == nil {
originalPosition = CGPoint(x: points.last!.x, y: points.last!.y)
}
let lastIndex = points.count - 1
points[lastIndex].x = originalPosition!.x + value.translation.width
points[lastIndex].y = originalPosition!.y + value.translation.height
}
.onEnded { value in
originalPosition = nil
}
}
private var addNewPointGesture: some Gesture {
TapGesture(count: 2)
.onEnded {
points.append(Point(context: viewContext))
}
}
var body: some View {
GeometryReader { geometry in
Group {
ShapeTest(points: points.map { CGPoint(x: [=11=].x, y: [=11=].y) })
.stroke()
}
.contentShape(Rectangle())
.gesture(movePointDragGesture.simultaneously(with: addNewPointGesture))
}
}
}
struct RedrawEdgeTestCoreData_Previews: PreviewProvider {
static var previews: some View {
RedrawEdgeTestCoreData()
.environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}
}
使用核心数据的版本在拖动时不会更新。当我双击添加另一个点时它会重绘。
关于发生这种情况的原因有什么建议吗?
我使用了 jnpdx 建议的方法并且有效。
import SwiftUI
class PointsViewModel: ObservableObject {
@Published var points = [Point]()
func movePoint(index: Int, x: CGFloat, y: CGFloat) {
points[index].x = x
points[index].y = y
objectWillChange.send()
}
}
struct RedrawEdgeTestCoreData: View {
@Environment(\.managedObjectContext) private var viewContext
@ObservedObject var viewModel: PointsViewModel
@State var originalPosition: CGPoint? = nil
private var movePointDragGesture: some Gesture {
DragGesture(minimumDistance: 0, coordinateSpace: .local)
.onChanged { value in
if viewModel.points.isEmpty {
return
}
if originalPosition == nil {
originalPosition = CGPoint(x: viewModel.points.last!.x, y: viewModel.points.last!.y)
}
let lastIndex = viewModel.points.count - 1
viewModel.movePoint(index: lastIndex, x: originalPosition!.x + value.translation.width, y: originalPosition!.y + value.translation.height)
}
.onEnded { value in
originalPosition = nil
}
}
private var addNewPointGesture: some Gesture {
TapGesture(count: 2)
.onEnded {
viewModel.points.append(Point(context: viewContext))
}
}
var body: some View {
GeometryReader { geometry in
ZStack {
ShapeTest(points: viewModel.points.map { CGPoint(x: [=10=].x, y: [=10=].y) })
.stroke()
}
.contentShape(Rectangle())
.gesture(movePointDragGesture.simultaneously(with: addNewPointGesture))
}
}
}
struct RedrawEdgeTestCoreData_Previews: PreviewProvider {
static var previews: some View {
RedrawEdgeTestCoreData(viewModel: PointsViewModel())
.environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}
}
我对这个问题一头雾水,过去几天我一直在解决这个问题。
我正在绘制自定义形状,用户可以通过拖动手势移动其中一个点。我希望在移动点时重新绘制形状。
这是一些使用 CGPoint 的示例代码。
import SwiftUI
struct ShapeTest: Shape {
@State var points: [CGPoint]
@State var closed: Bool = true
func path(in rect: CGRect) -> Path {
var path = Path()
if (points.count > 0) {
path.move(to: points.first!)
path.addLines(points)
if closed { path.closeSubpath() }
}
return path
}
}
struct RedrawEdgeTestCGPoint: View {
@State var points = [CGPoint]()
@State var originalPosition: CGPoint? = nil
private var movePointDragGesture: some Gesture {
DragGesture(minimumDistance: 0, coordinateSpace: .local)
.onChanged { value in
if points.isEmpty {
return
}
if originalPosition == nil {
originalPosition = CGPoint(x: points.last!.x, y: points.last!.y)
}
let lastIndex = points.count - 1
points[lastIndex].x = originalPosition!.x + value.translation.width
points[lastIndex].y = originalPosition!.y + value.translation.height
}
.onEnded { value in
originalPosition = nil
}
}
private var addNewPointGesture: some Gesture {
TapGesture(count: 2)
.onEnded {
points.append(CGPoint())
}
}
var body: some View {
GeometryReader { geometry in
Group {
ShapeTest(points: points)
.stroke()
}
.contentShape(Rectangle())
.gesture(movePointDragGesture.simultaneously(with: addNewPointGesture))
}
}
}
struct RedrawEdgeTestCGPoint_Previews: PreviewProvider {
static var previews: some View {
RedrawEdgeTestCGPoint()
}
}
现在,这是另一个代码示例。这个例子大体上是一样的,但这是使用我在 Core Data 中定义的 Point 实体而不是 CGPoint。
import SwiftUI
struct RedrawEdgeTestCoreData: View {
@Environment(\.managedObjectContext) private var viewContext
@State var points: [Point] = []
@State var originalPosition: CGPoint? = nil
private var movePointDragGesture: some Gesture {
DragGesture(minimumDistance: 0, coordinateSpace: .local)
.onChanged { value in
if points.isEmpty {
return
}
if originalPosition == nil {
originalPosition = CGPoint(x: points.last!.x, y: points.last!.y)
}
let lastIndex = points.count - 1
points[lastIndex].x = originalPosition!.x + value.translation.width
points[lastIndex].y = originalPosition!.y + value.translation.height
}
.onEnded { value in
originalPosition = nil
}
}
private var addNewPointGesture: some Gesture {
TapGesture(count: 2)
.onEnded {
points.append(Point(context: viewContext))
}
}
var body: some View {
GeometryReader { geometry in
Group {
ShapeTest(points: points.map { CGPoint(x: [=11=].x, y: [=11=].y) })
.stroke()
}
.contentShape(Rectangle())
.gesture(movePointDragGesture.simultaneously(with: addNewPointGesture))
}
}
}
struct RedrawEdgeTestCoreData_Previews: PreviewProvider {
static var previews: some View {
RedrawEdgeTestCoreData()
.environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}
}
使用核心数据的版本在拖动时不会更新。当我双击添加另一个点时它会重绘。
关于发生这种情况的原因有什么建议吗?
我使用了 jnpdx 建议的方法并且有效。
import SwiftUI
class PointsViewModel: ObservableObject {
@Published var points = [Point]()
func movePoint(index: Int, x: CGFloat, y: CGFloat) {
points[index].x = x
points[index].y = y
objectWillChange.send()
}
}
struct RedrawEdgeTestCoreData: View {
@Environment(\.managedObjectContext) private var viewContext
@ObservedObject var viewModel: PointsViewModel
@State var originalPosition: CGPoint? = nil
private var movePointDragGesture: some Gesture {
DragGesture(minimumDistance: 0, coordinateSpace: .local)
.onChanged { value in
if viewModel.points.isEmpty {
return
}
if originalPosition == nil {
originalPosition = CGPoint(x: viewModel.points.last!.x, y: viewModel.points.last!.y)
}
let lastIndex = viewModel.points.count - 1
viewModel.movePoint(index: lastIndex, x: originalPosition!.x + value.translation.width, y: originalPosition!.y + value.translation.height)
}
.onEnded { value in
originalPosition = nil
}
}
private var addNewPointGesture: some Gesture {
TapGesture(count: 2)
.onEnded {
viewModel.points.append(Point(context: viewContext))
}
}
var body: some View {
GeometryReader { geometry in
ZStack {
ShapeTest(points: viewModel.points.map { CGPoint(x: [=10=].x, y: [=10=].y) })
.stroke()
}
.contentShape(Rectangle())
.gesture(movePointDragGesture.simultaneously(with: addNewPointGesture))
}
}
}
struct RedrawEdgeTestCoreData_Previews: PreviewProvider {
static var previews: some View {
RedrawEdgeTestCoreData(viewModel: PointsViewModel())
.environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}
}