LoginSignup
0
1

More than 1 year has passed since last update.

SwiftUIでオブジェクトの移動

Last updated at Posted at 2022-08-26

これは備忘録メモ
SwiftUIでアノテーションツールを作ろうかと思ったらオブジェクトのドラッグ&ドロップのやり方がよくわからなくてハマる。
次に値を取ってこようとしたら、慣れていないのでBindingの書き方がわからなくて値を取ってこれない。
ちょっとしたことも慣れてないと難しい。

demo.gif

import SwiftUI

extension View {
  func draggable(into binding: Binding<CGPoint>) -> some View {
    self.modifier(DraggableModifier(offset: binding))
  }
}

struct DraggableModifier: ViewModifier {
  @Binding var offset: CGPoint
  @State private var previousTranslation: CGSize?

  func body(content: Content) -> some View {
    
    content
      .offset(x: offset.x, y: offset.y)
      .gesture(DragGesture().onChanged { value in
        if let translation = previousTranslation {
          // Drag changed
          let delta = CGSize(width: value.translation.width - translation.width,
                             height: value.translation.height - translation.height)
          offset.x += delta.width
          offset.y += delta.height
          previousTranslation = value.translation
        } else {
          // Drag started
          previousTranslation = value.translation
        }
      }
      .onEnded { _ in
        // Drag ended
        previousTranslation = nil
      })
  }
}

struct Shape {
  var offset: CGPoint = .zero
  var view: AnyView
  init(_ view: AnyView){
    self.view = view
  }
}

struct ContentView: View {
  @State private var location: CGPoint = CGPoint(x: 0, y: 0)
  @State var offset: CGPoint = .zero
  @State private var shapes: [Shape] = [
    Shape(
      AnyView (
        Rectangle().fill(Color.red)
          .frame(width: 100, height: 100)
      )),
    Shape(
      AnyView (
        Circle().fill(Color.blue)
          .frame(width: 100, height: 100)
      ))
  ]

  var body: some View {
    ZStack {
      Rectangle()
        .fill(Color.clear)
      
        VStack {
          ForEach(shapes.indices, id: \.self) {
            shapes[$0].view.draggable(into: $shapes[$0].offset)
            Text("Offset: \(shapes[$0].offset.x)")
          }
        }
    }.contentShape(Rectangle())
    }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}

修正版

前回のoffset版では、タップした位置の座標は返すがオブジェクトの座標を返していなかったので修正

demo.gif

import SwiftUI

extension View {
  func draggable(into binding: Binding<CGPoint>) -> some View {
    self.modifier(DraggableModifier(location: binding))
  }
}

struct DraggableModifier: ViewModifier {
  @Binding var location: CGPoint
  @GestureState private var startLocation: CGPoint? = nil

  func body(content: Content) -> some View {
    
    content
      .position(x: location.x, y: location.y)
      .gesture(
        DragGesture()
          .onChanged { value in
            var newLocation = startLocation ?? location
            newLocation.x += value.translation.width
            newLocation.y += value.translation.height
            self.location = newLocation
          }
          .updating($startLocation) { (value, startLocation, transaction) in
            startLocation = startLocation ?? location
          }
      )
  }
}

struct Shape {
  var location: CGPoint = .zero
  var view: AnyView
  init(_ view: AnyView, location: CGPoint){
    self.view = view
    self.location = location
  }
}

struct ContentView: View {
  @State private var shapes: [Shape] = [
    Shape(
      AnyView (
        Rectangle().fill(Color.red)
          .frame(width: 50, height: 50).offset(x: 25,y: 25)
      ), location: CGPoint(x: 0, y: 0)),
    Shape(
      AnyView (
        Circle().fill(Color.blue)
          .frame(width: 50, height: 50).offset(x: 25,y: 25)
      ), location: CGPoint(x: 100, y: 100))
  ]

  var body: some View {
    ZStack {
      Rectangle()
        .fill(Color.clear)
      
        ForEach(shapes.indices, id: \.self) {
          shapes[$0].view.draggable(into: $shapes[$0].location)
        }
        VStack {
          ForEach(shapes.indices, id: \.self) {
            Text("Location: \(shapes[$0].location.x), \(shapes[$0].location.y)")
          }
        }
    }.contentShape(Rectangle())
  }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}

参考サイト

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1