Last active
November 2, 2022 01:14
-
-
Save Wilsonilo/d6b4aece2a49d697b1f81559278c5d6c to your computer and use it in GitHub Desktop.
Drag and Drop SwiftUI with ScrollView and HStack
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//: HSTack /Scroll View With Drag and Drop | |
// By Wilson Munoz / @yosoywil | |
// Inspiration 1: https://gist.github.com/tarasis/f9bac6d98de5433f1ddbadaef02f9a29 | |
// Inspiration 2: https://swiftui-lab.com/drag-drop-with-swiftui/ | |
// Really dirty but functional, need to stress test with several items in the ScrollView/HStack and check memory. | |
import SwiftUI | |
import PlaygroundSupport | |
import Combine | |
protocol middleManProtocol { | |
func swapPerson(myName:String, nameMovingElement:String)->Bool | |
} | |
class MiddleMan:ObservableObject{ | |
@Published var people = [PersonRow]() | |
} | |
struct Person: Identifiable, Hashable { | |
var id = UUID() | |
var name: String | |
} | |
struct PersonRow: View, Identifiable { | |
var id = UUID() | |
var person: Person | |
@State var targeted: Bool = true | |
var delegate: middleManProtocol | |
@State var positionOnScroll:CGPoint = .zero | |
var body: some View { | |
HStack { | |
Image(systemName: "person.circle") | |
Text(person.name) | |
Text(person.id.description) | |
} | |
.onDrop(of: ["public.utf8-plain-text"], isTargeted: self.$targeted, | |
perform: { (provider) -> Bool in | |
guard let personSwaping = provider.first, let name = personSwaping.suggestedName | |
else { return false} | |
return self.delegate.swapPerson(myName: self.person.id.uuidString, | |
nameMovingElement: name) | |
}) | |
.onDrag { | |
let item = NSItemProvider(object: NSString(string: self.person.name)) | |
item.suggestedName = self.person.id.uuidString | |
return item | |
} | |
} | |
} | |
struct MyView : View, middleManProtocol{ | |
func swapPerson(myName:String, nameMovingElement:String)->Bool{ | |
print("swap running") | |
//Get index of person (me) and get the index of the one moving | |
guard let indexOfElementMoving = self.delegate.people.firstIndex(where: {$0.person.id.uuidString == nameMovingElement}) else { | |
return false} | |
print("got index of moving provider", indexOfElementMoving) | |
guard let myIndex = self.delegate.people.firstIndex(where: {$0.person.id.uuidString == myName}) else {return false} | |
print("got my index", myIndex) | |
//Swap | |
self.delegate.people.swapAt(myIndex, indexOfElementMoving) | |
return true | |
} | |
@ObservedObject var delegate: MiddleMan = MiddleMan() | |
@State var targeted: Bool = true | |
var body: some View { | |
ScrollView(.horizontal, showsIndicators: true){ | |
HStack { | |
ForEach(delegate.people) { person in | |
person | |
.frame(width: 100, height:100) | |
} | |
}.frame(height:100) | |
}.onAppear { | |
//Do your call to server or model or whatever | |
//I don't like the delegate setter like this, pretty sure i can create a better approach, just doing it like this for now. | |
self.delegate.people = [ | |
PersonRow(person: Person(name: "George"), delegate: self), | |
PersonRow(person: Person(name: "Michael"), delegate: self), | |
PersonRow(person: Person(name: "Wilson"), delegate: self), | |
PersonRow(person: Person(name: "Jocko"), delegate: self), | |
PersonRow(person: Person(name: "Jhon"), delegate: self) | |
] | |
} | |
} | |
} | |
// Present the view controller in the Live View window | |
PlaygroundPage.current.setLiveView(MyView()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment