SwiftUI拖動變換位置

實現(xiàn)一下SwiftUI拖動變化位置的功能。
涉及到的是使用 onDrag 和 onDrop 屬性。
大體的思路就是在 onDrag 中記錄下移動中的元素, 在 onDrop 中根據(jù)移動到的位置改變移動元素插入的位置。
有兩個版本效果。

1. 首先簡單版本效果。

drop.gif

代碼如下:

import SwiftUI

struct Test: View {
    @State private var targeted = true
    @State private var tags = [0,1,2,3,4,5,6,7,8,9,10]
    
    var body: some View {
        let adaColumns = [
            GridItem(.adaptive(minimum: 60, maximum: 80))]
        
        VStack {
            LazyVGrid(columns: adaColumns) {
                ForEach(tags, id: \.self) { tag in
                    Text("\(tag)")
                        .font(.subheadline)
                        .padding(.vertical, 8)
                        .frame(maxWidth: .infinity)
                        .background(
                            Color.init(hexString: "#dddddd")
                        )
                        .cornerRadius(4)
                        .onDrag {
                            let item = NSItemProvider(object: NSString(string: "\(tag)"))
                            item.suggestedName = "\(tag)"
                            return item
                        }
                        .onDrop(of: [.text], isTargeted: $targeted) { providers in
                            print("drop \(providers.first) \(tag)")
                            guard let provider = providers.first, let item = provider.suggestedName else {
                                return false
                            }
                            let a = Int(item)
                            let i = tags.firstIndex(of: a!)
                            withAnimation {
                                tags.remove(at: I!)
                                let j = tags.firstIndex(of: tag)
                                tags.insert(a!, at: j!)
                            }
                            return true
                        }
                }
            }
            .frame(maxWidth: .infinity)
        }
        .padding()
    }
}

struct Test_Previews: PreviewProvider {
    static var previews: some View {
        Test()
    }
}

改進版效果

使用到了 DropDelegate 協(xié)議,能夠獲取移動中和碰撞的兩個元素的事件,能夠在運動中進行控制,方便實現(xiàn)更完美的動畫。


update.gif
import SwiftUI
import UniformTypeIdentifiers

final class TModel: NSObject {
    var id: UUID
    var tag: String
    
    internal init(id: UUID, tag: String) {
        self.id = id
        self.tag = tag
    }
}

enum MoveEnum: Int {
    case left
    case right
}

struct DragRelocateDelegate: DropDelegate {
    let item: TModel
    var listData: [TModel]
    @Binding var current: TModel?
    
    var moveAction: (MoveEnum) -> Void
    
    func dropEntered(info: DropInfo) {
    }
    
    func dropUpdated(info: DropInfo) -> DropProposal? {
        print("update location.x is \(info.location.x)")
        if item != current {
            if info.location.x > 30 {
                moveAction(.right)
            } else {
                moveAction(.left)
            }
        }

        return DropProposal(operation: .move)
    }
    
    func performDrop(info: DropInfo) -> Bool {
        return true
    }
}

struct Test1: View {
    @State private var targeted = true
    @State private var tags:[TModel]
    @State var dragTag: TModel?

    init() {
        var __tags:[TModel] = []
        for i in 0...10 {
            __tags.append(TModel.init(id: UUID(), tag: "\(i)"))
        }
        _tags = State.init(initialValue: __tags)
    }
    
    var body: some View {
        
        let adaColumns = [
            GridItem(.adaptive(minimum: 60, maximum: 80))]
        
        VStack {
            LazyVGrid(columns: adaColumns) {
                ForEach(tags, id: \.id) { item in
                    Text(item.tag)
                        .font(.subheadline)
                        .padding(.vertical, 8)
                        .frame(maxWidth: .infinity)
                        .background(
                            Color.init(hexString: "#dddddd")
                        )
                        .cornerRadius(4)
                        .onDrag {
                            let provider = NSItemProvider(object: NSString(string: item.id.uuidString))
                            provider.suggestedName = "tags"
                            
                            dragTag = item
                            return provider
                        }
                        .onDrop(of: [.text], delegate: DragRelocateDelegate(item: item, listData: tags, current: $dragTag, moveAction: { direction in
                            if item == dragTag {
                                return
                            }
                            
                            let i = tags.firstIndex(of: dragTag!)
                            withAnimation {
                                tags.remove(at: I!)
                                let j = tags.firstIndex(of: item)
                                if direction == .left {
                                    tags.insert(dragTag!, at: j!)
                                } else {
                                    tags.insert(dragTag!, at: j! + 1)
                                }
                            }
                        }))
                }
            }
            .frame(maxWidth: .infinity)
        }
        .padding()
    }
}

struct Test1_Previews: PreviewProvider {
    static var previews: some View {
        Test1()
    }
}
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 可以對比參照UIKit中的UIView 了解swift的人都知道,swift是一門基于協(xié)議的語言,同樣swiftU...
    水之飛亦閱讀 580評論 0 1
  • 實戰(zhàn)需求 macOS SwiftUI 技巧之圖片文件拖拽到app并顯示 本文價值與收獲 看完本文后,您將能夠作出下...
    iCloudEnd閱讀 1,180評論 0 2
  • 一、HTML5 1.1 認識HTML5 HTML5并不僅僅只是作為HTML標記語言的一個最新版本,更重要的是它制定...
    小雨不會閱讀 335評論 0 0
  • 一、HTML5 1.1 認識HTML5 HTML5并不僅僅只是作為HTML標記語言的一個最新版本,更重要的是它制定...
    福爾摩雞閱讀 16,506評論 14 51
  • 1、HTML5:HTML4.1網(wǎng)頁開發(fā):結構: html4.0樣式:css css2行為:jsHTML5:是HTM...
    Yuann閱讀 927評論 0 2

友情鏈接更多精彩內(nèi)容