Last active
November 3, 2023 23:19
-
-
Save byaruhaf/9f06ff1d058bfccc06539dae7f9a51db to your computer and use it in GitHub Desktop.
PhotosGridViewDraggableX
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
// | |
// ContentView.swift | |
// TestDrag | |
// | |
// Created by Franklin Byaruhanga on 23/09/2023. | |
// | |
import SwiftUI | |
struct ColorItemView: View { | |
let url: URL | |
let cellSize: CGSize | |
var body: some View { | |
AsyncImage(url: url) { phase in | |
switch phase { | |
case .success(let image): | |
image | |
.resizable() | |
.scaledToFill() | |
default: | |
ProgressView() | |
} | |
} | |
.cornerRadius(15) | |
.frame(width: cellSize.width, height: cellSize.height) | |
.clipped() | |
} | |
} | |
struct DropViewDelegate: DropDelegate { | |
let destinationItem: URL | |
@Binding var colors: [URL] | |
@Binding var draggedItem: URL? | |
@Binding var lastUpdated: Date? // this is new! | |
@Binding var isDrop: Bool | |
func dropExited(info: DropInfo) { | |
self.isDrop = false | |
} | |
func dropUpdated(info: DropInfo) -> DropProposal? { | |
DropProposal(operation: .move) | |
} | |
func performDrop(info: DropInfo) -> Bool { | |
draggedItem = nil | |
return true | |
} | |
func dropEntered(info: DropInfo) { | |
self.isDrop = true | |
// Swap Items | |
if let draggedItem { | |
let fromIndex = colors.firstIndex(of: draggedItem) | |
if let fromIndex { | |
let toIndex = colors.firstIndex(of: destinationItem) | |
if let toIndex, fromIndex != toIndex { | |
let now: Date = .now | |
if (lastUpdated == nil || now.timeIntervalSince(lastUpdated!) > 0.2) { | |
lastUpdated = .now | |
withAnimation { | |
self.colors.move(fromOffsets: IndexSet(integer: fromIndex), toOffset: (toIndex > fromIndex ? (toIndex + 1) : toIndex)) | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
struct PhotosGridViewDraggableX: View { | |
@State private var draggedColor: URL? | |
@State var colors: [URL] = [ | |
URL(string: "https://picsum.photos/id/1/500/500")!, | |
URL(string: "https://picsum.photos/id/20/500/500")!, | |
URL(string: "https://picsum.photos/id/50/500/500")!, | |
URL(string: "https://picsum.photos/id/100/500/500")!, | |
URL(string: "https://picsum.photos/id/67/500/500")!, | |
URL(string: "https://picsum.photos/id/6/500/500")! | |
] | |
@State private var lastUpdated: Date? // this is new! | |
@State var isDrop: Bool = false | |
var body: some View { | |
GeometryReader { proxy in | |
let hGap: CGFloat = 14 | |
let width = proxy.size.width - (hGap * 2) | |
let cellWidth = (width / 3) | |
let cellSize = CGSize(width: cellWidth, height: cellWidth * 1.5) | |
let columns = [GridItem(.fixed(cellWidth)), GridItem(.fixed(cellWidth)), GridItem(.fixed(cellWidth))] | |
LazyVGrid(columns: columns) { | |
ForEach(colors, id: \.self) { color in | |
ColorItemView(url: color, cellSize: cellSize) | |
.overlay( | |
(isDrop && (color == draggedColor)) | |
? Rectangle().fill(.thinMaterial) | |
: nil | |
) | |
// .opacity( (isDrop && (color == draggedColor)) ? 0.01 : 1) | |
.onDrag { | |
self.draggedColor = color | |
return NSItemProvider() | |
} preview: { | |
ColorItemView(url: color, cellSize: cellSize) | |
.opacity(1) | |
} | |
.onDrop(of: [.text], | |
delegate: DropViewDelegate(destinationItem: color, colors: $colors, draggedItem: $draggedColor, lastUpdated: $lastUpdated, isDrop: $isDrop) | |
) | |
} | |
} | |
} | |
} | |
} | |
#Preview { | |
PhotosGridViewDraggableX() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I used this:
this is the video see how the onDrag Preview does not always work
sample.mp4