드래그 가능한 그리드를 만드는 것을 연습해보았다.
아마도 온리픽원 새로운 기능에 추가될 수 있을 것 같다.
우선 SwiftUI View를 하나 추가해서 여러 가지 색깔의 View를 그리드에 나타낸다.
import SwiftUI
struct MovableGridView: View {
@State private var colors: [Color] = [.red, .blue, .green, .purple, .orange, .yellow, .brown, .cyan, .indigo, .mint, .pink, .black]
var body: some View {
ScrollView(.vertical) {
let columns = Array(repeating: GridItem(spacing: 10), count: 3)
LazyVGrid(columns: columns) {
ForEach(colors, id: \.self) { color in
RoundedRectangle(cornerRadius: 10)
.fill(color.gradient)
.frame(height: 100)
}
}
.padding(15)
}
.navigationTitle("드래그 그리드")
}
}
위와 같이 12개의 색깔 View가 적절히 표시되게 할 수 있다.
다음으로 View 하나를 드래그해서 다른 View들 사이로 옮기는 것을 구현한다.
우선 draggable을 통해 하나의 View를 선택하는 것을 구현할 수 있다.
var body: some View {
ScrollView(.vertical) {
let columns = Array(repeating: GridItem(spacing: 10), count: 3)
LazyVGrid(columns: columns) {
ForEach(colors, id: \.self) { color in
GeometryReader {
let size = $0.size
RoundedRectangle(cornerRadius: 10)
.fill(color.gradient)
.draggable(color) {
RoundedRectangle(cornerRadius: 10)
.fill(.ultraThinMaterial)
.frame(width: size.width, height: size.height)
.onAppear {
draggingItem = color
}
}
}
.frame(height: 120)
}
}
.padding(15)
}
.navigationTitle("드래그 그리드")
}
하나의 View를 꾹 눌러서 옮기면 draggable 안에 구현한 새로운 반투명한 View가 떠다니면서 드래그가 구현됨을 확인할 수 있다.
실제로 View를 다른 위치로 이동 시키기 위해서는 이 반투명한 View가 현재 어떤 위치에 있는지 확인을 해야한다.
먼저 현재 선택된 View를 상태 값에 저장한다.
다음으로 dropDestination을 활용해서 현재 선택된 View가 어느 위치에 있는지 확인을 한다.
/// 현재 드래그 중인 아이템
@State private var draggingItem: Color?
RoundedRectangle(cornerRadius: 10)
.fill(color.gradient)
.draggable(color) {
RoundedRectangle(cornerRadius: 10)
.fill(.ultraThinMaterial)
.frame(width: size.width, height: size.height)
.onAppear {
draggingItem = color
}
}
.dropDestination(for: Color.self) { items, location in
return false
} isTargeted: { status in
print(color)
}
이렇게 하면 드래그 중 현재 위치의 color가 콘솔에 출력되는 것을 확인할 수 있다.
드래그 중인 color의 인덱스와 현재 위치 color의 인덱스를 구해서 colors의 리스트 순서를 변경한다.
withAnimation을 활용하면 자연스럽게 View들이 재정렬되는 것을 확인할 수 있다.
.dropDestination(for: Color.self) { items, location in
draggingItem = nil
return false
} isTargeted: { status in
if let draggingItem, status, draggingItem != color {
if let from = colors.firstIndex(of: draggingItem),
let to = colors.firstIndex(of: color) {
withAnimation(.easeInOut) {
let sourceItem = colors.remove(at: from)
colors.insert(sourceItem, at: to)
}
}
}
}
전체 코드 Repo
https://github.com/110w110/SwiftUIExample/tree/master
GitHub - 110w110/SwiftUIExample
Contribute to 110w110/SwiftUIExample development by creating an account on GitHub.
github.com
'Swift > SwiftUI' 카테고리의 다른 글
[SwiftUI] 성공과 실패 애니메이션을 포함한 버튼 커스텀하기 (1) | 2024.01.22 |
---|